Skip to content

Commit ea0d998

Browse files
varkoryodaldevoid
andcommitted
Add resolution errors for const generics
Co-Authored-By: Gabriel Smith <[email protected]>
1 parent b4ef753 commit ea0d998

File tree

2 files changed

+146
-32
lines changed

2 files changed

+146
-32
lines changed

src/librustc_resolve/lib.rs

Lines changed: 126 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ use syntax::ast::{FnDecl, ForeignItem, ForeignItemKind, GenericParamKind, Generi
5151
use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
5252
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
5353
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
54+
use syntax::ast::ParamKindOrd;
5455
use syntax::ptr::P;
5556
use syntax::{span_err, struct_span_err, unwrap_or, walk_list};
5657

@@ -142,10 +143,11 @@ impl Ord for BindingError {
142143
}
143144

144145
enum ResolutionError<'a> {
145-
/// error E0401: can't use type parameters from outer function
146-
TypeParametersFromOuterFunction(Def),
147-
/// error E0403: the name is already used for a type parameter in this type parameter list
148-
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
146+
/// error E0401: can't use type or const parameters from outer function
147+
ParametersFromOuterFunction(Def, ParamKindOrd),
148+
/// error E0403: the name is already used for a type/const parameter in this list of
149+
/// generic parameters
150+
NameAlreadyUsedInParameterList(Name, &'a Span),
149151
/// error E0407: method is not a member of trait
150152
MethodNotMemberOfTrait(Name, &'a str),
151153
/// error E0437: type is not a member of trait
@@ -177,7 +179,9 @@ enum ResolutionError<'a> {
177179
/// error E0530: X bindings cannot shadow Ys
178180
BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
179181
/// error E0128: type parameters with a default cannot use forward declared identifiers
180-
ForwardDeclaredTyParam,
182+
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
183+
/// error E0670: const parameter cannot depend on type parameter
184+
ConstParamDependentOnTypeParam,
181185
}
182186

183187
/// Combines an error with provided span and emits it
@@ -195,12 +199,14 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
195199
resolution_error: ResolutionError<'a>)
196200
-> DiagnosticBuilder<'sess> {
197201
match resolution_error {
198-
ResolutionError::TypeParametersFromOuterFunction(outer_def) => {
202+
ResolutionError::ParametersFromOuterFunction(outer_def, kind) => {
199203
let mut err = struct_span_err!(resolver.session,
200-
span,
201-
E0401,
202-
"can't use type parameters from outer function");
203-
err.span_label(span, "use of type variable from outer function");
204+
span,
205+
E0401,
206+
"can't use {} parameters from outer function",
207+
kind,
208+
);
209+
err.span_label(span, format!("use of {} variable from outer function", kind));
204210

205211
let cm = resolver.session.source_map();
206212
match outer_def {
@@ -224,20 +230,25 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
224230
}
225231
return err;
226232
},
227-
Def::TyParam(typaram_defid) => {
228-
if let Some(typaram_span) = resolver.definitions.opt_span(typaram_defid) {
229-
err.span_label(typaram_span, "type variable from outer function");
233+
Def::TyParam(def_id) => {
234+
if let Some(span) = resolver.definitions.opt_span(def_id) {
235+
err.span_label(span, "type variable from outer function");
230236
}
231-
},
237+
}
238+
Def::ConstParam(def_id) => {
239+
if let Some(span) = resolver.definitions.opt_span(def_id) {
240+
err.span_label(span, "const variable from outer function");
241+
}
242+
}
232243
_ => {
233-
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy or \
234-
Def::TyParam")
244+
bug!("TypeParametersFromOuterFunction should only be used with Def::SelfTy, \
245+
Def::TyParam or Def::ConstParam");
235246
}
236247
}
237248

238249
// Try to retrieve the span of the function signature and generate a new message with
239-
// a local type parameter
240-
let sugg_msg = "try using a local type parameter instead";
250+
// a local type or const parameter.
251+
let sugg_msg = &format!("try using a local {} parameter instead", kind);
241252
if let Some((sugg_span, new_snippet)) = cm.generate_local_type_param_snippet(span) {
242253
// Suggest the modification to the user
243254
err.span_suggestion(
@@ -247,19 +258,20 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
247258
Applicability::MachineApplicable,
248259
);
249260
} else if let Some(sp) = cm.generate_fn_name_span(span) {
250-
err.span_label(sp, "try adding a local type parameter in this method instead");
261+
err.span_label(sp,
262+
format!("try adding a local {} parameter in this method instead", kind));
251263
} else {
252-
err.help("try using a local type parameter instead");
264+
err.help(&format!("try using a local {} parameter instead", kind));
253265
}
254266

255267
err
256268
}
257-
ResolutionError::NameAlreadyUsedInTypeParameterList(name, first_use_span) => {
269+
ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => {
258270
let mut err = struct_span_err!(resolver.session,
259271
span,
260272
E0403,
261-
"the name `{}` is already used for a type parameter \
262-
in this type parameter list",
273+
"the name `{}` is already used for a generic \
274+
parameter in this list of generic parameters",
263275
name);
264276
err.span_label(span, "already used");
265277
err.span_label(first_use_span.clone(), format!("first use of `{}`", name));
@@ -416,6 +428,12 @@ fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver<'_>,
416428
span, "defaulted type parameters cannot be forward declared".to_string());
417429
err
418430
}
431+
ResolutionError::ConstParamDependentOnTypeParam => {
432+
let mut err = struct_span_err!(resolver.session, span, E0670,
433+
"const parameters cannot depend on type parameters");
434+
err.span_label(span, format!("const parameter depends on type parameter"));
435+
err
436+
}
419437
}
420438
}
421439

@@ -546,7 +564,7 @@ impl<'a> PathSource<'a> {
546564
Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
547565
Def::Trait(..) | Def::TraitAlias(..) | Def::TyAlias(..) |
548566
Def::AssociatedTy(..) | Def::PrimTy(..) | Def::TyParam(..) |
549-
Def::SelfTy(..) | Def::Existential(..) |
567+
Def::SelfTy(..) | Def::Existential(..) | Def::ConstParam(..) |
550568
Def::ForeignTy(..) => true,
551569
_ => false,
552570
},
@@ -564,7 +582,7 @@ impl<'a> PathSource<'a> {
564582
Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) |
565583
Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) |
566584
Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) |
567-
Def::SelfCtor(..) => true,
585+
Def::SelfCtor(..) | Def::ConstParam(..) => true,
568586
_ => false,
569587
},
570588
PathSource::Pat => match def {
@@ -855,6 +873,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
855873
self.label_ribs.pop();
856874
self.ribs[ValueNS].pop();
857875
}
876+
858877
fn visit_generics(&mut self, generics: &'tcx Generics) {
859878
// For type parameter defaults, we have to ban access
860879
// to following type parameters, as the Substs can only
@@ -865,6 +884,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
865884
let mut found_default = false;
866885
default_ban_rib.bindings.extend(generics.params.iter()
867886
.filter_map(|param| match param.kind {
887+
GenericParamKind::Const { .. } |
868888
GenericParamKind::Lifetime { .. } => None,
869889
GenericParamKind::Type { ref default, .. } => {
870890
found_default |= default.is_some();
@@ -876,6 +896,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
876896
}
877897
}));
878898

899+
// We also ban access to type parameters for use as the types of const parameters.
900+
let mut const_ty_param_ban_rib = Rib::new(TyParamAsConstParamTy);
901+
const_ty_param_ban_rib.bindings.extend(generics.params.iter()
902+
.filter(|param| if let GenericParamKind::Type { .. } = param.kind {
903+
true
904+
} else {
905+
false
906+
})
907+
.map(|param| (Ident::with_empty_ctxt(param.ident.name), Def::Err)));
908+
879909
for param in &generics.params {
880910
match param.kind {
881911
GenericParamKind::Lifetime { .. } => self.visit_generic_param(param),
@@ -893,6 +923,17 @@ impl<'a, 'tcx> Visitor<'tcx> for Resolver<'a> {
893923
// Allow all following defaults to refer to this type parameter.
894924
default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
895925
}
926+
GenericParamKind::Const { ref ty } => {
927+
self.ribs[TypeNS].push(const_ty_param_ban_rib);
928+
929+
for bound in &param.bounds {
930+
self.visit_param_bound(bound);
931+
}
932+
933+
self.visit_ty(ty);
934+
935+
const_ty_param_ban_rib = self.ribs[TypeNS].pop().unwrap();
936+
}
896937
}
897938
}
898939
for p in &generics.where_clause.predicates {
@@ -944,6 +985,9 @@ enum RibKind<'a> {
944985
/// from the default of a type parameter because they're not declared
945986
/// before said type parameter. Also see the `visit_generics` override.
946987
ForwardTyParamBanRibKind,
988+
989+
/// We forbid the use of type parameters as the types of const parameters.
990+
TyParamAsConstParamTy,
947991
}
948992

949993
/// One local scope.
@@ -2535,7 +2579,7 @@ impl<'a> Resolver<'a> {
25352579

25362580
if seen_bindings.contains_key(&ident) {
25372581
let span = seen_bindings.get(&ident).unwrap();
2538-
let err = ResolutionError::NameAlreadyUsedInTypeParameterList(
2582+
let err = ResolutionError::NameAlreadyUsedInParameterList(
25392583
ident.name,
25402584
span,
25412585
);
@@ -2548,6 +2592,24 @@ impl<'a> Resolver<'a> {
25482592
function_type_rib.bindings.insert(ident, def);
25492593
self.record_def(param.id, PathResolution::new(def));
25502594
}
2595+
GenericParamKind::Const { .. } => {
2596+
let ident = param.ident.modern();
2597+
debug!("with_type_parameter_rib: {}", param.id);
2598+
2599+
if seen_bindings.contains_key(&ident) {
2600+
let span = seen_bindings.get(&ident).unwrap();
2601+
let err = ResolutionError::NameAlreadyUsedInParameterList(
2602+
ident.name,
2603+
span,
2604+
);
2605+
resolve_error(self, param.ident.span, err);
2606+
}
2607+
seen_bindings.entry(ident).or_insert(param.ident.span);
2608+
2609+
let def = Def::ConstParam(self.definitions.local_def_id(param.id));
2610+
function_type_rib.bindings.insert(ident, def);
2611+
self.record_def(param.id, PathResolution::new(def));
2612+
}
25512613
}
25522614
}
25532615
self.ribs[TypeNS].push(function_type_rib);
@@ -4106,6 +4168,15 @@ impl<'a> Resolver<'a> {
41064168
return Def::Err;
41074169
}
41084170

4171+
// An invalid use of a type parameter as the type of a const parameter.
4172+
if let TyParamAsConstParamTy = self.ribs[ns][rib_index].kind {
4173+
if record_used {
4174+
resolve_error(self, span, ResolutionError::ConstParamDependentOnTypeParam);
4175+
}
4176+
assert_eq!(def, Def::Err);
4177+
return Def::Err;
4178+
}
4179+
41094180
match def {
41104181
Def::Upvar(..) => {
41114182
span_bug!(span, "unexpected {:?} in bindings", def)
@@ -4114,7 +4185,7 @@ impl<'a> Resolver<'a> {
41144185
for rib in ribs {
41154186
match rib.kind {
41164187
NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
4117-
ForwardTyParamBanRibKind => {
4188+
ForwardTyParamBanRibKind | TyParamAsConstParamTy => {
41184189
// Nothing to do. Continue.
41194190
}
41204191
ClosureRibKind(function_id) => {
@@ -4167,21 +4238,44 @@ impl<'a> Resolver<'a> {
41674238
match rib.kind {
41684239
NormalRibKind | TraitOrImplItemRibKind | ClosureRibKind(..) |
41694240
ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind |
4170-
ConstantItemRibKind => {
4241+
ConstantItemRibKind | TyParamAsConstParamTy => {
41714242
// Nothing to do. Continue.
41724243
}
41734244
ItemRibKind => {
4174-
// This was an attempt to use a type parameter outside
4175-
// its scope.
4245+
// This was an attempt to use a type parameter outside its scope.
41764246
if record_used {
4177-
resolve_error(self, span,
4178-
ResolutionError::TypeParametersFromOuterFunction(def));
4247+
resolve_error(
4248+
self,
4249+
span,
4250+
ResolutionError::ParametersFromOuterFunction(
4251+
def,
4252+
ParamKindOrd::Type,
4253+
),
4254+
);
41794255
}
41804256
return Def::Err;
41814257
}
41824258
}
41834259
}
41844260
}
4261+
Def::ConstParam(..) => {
4262+
for rib in ribs {
4263+
if let ItemRibKind = rib.kind {
4264+
// This was an attempt to use a const parameter outside its scope.
4265+
if record_used {
4266+
resolve_error(
4267+
self,
4268+
span,
4269+
ResolutionError::ParametersFromOuterFunction(
4270+
def,
4271+
ParamKindOrd::Const,
4272+
),
4273+
);
4274+
}
4275+
return Def::Err;
4276+
}
4277+
}
4278+
}
41854279
_ => {}
41864280
}
41874281
def

src/libsyntax/ast.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,26 @@ impl GenericBound {
307307

308308
pub type GenericBounds = Vec<GenericBound>;
309309

310+
/// Specifies the enforced ordering for generic parameters. In the future,
311+
/// if we wanted to relax this order, we could override `PartialEq` and
312+
/// `PartialOrd`, to allow the kinds to be unordered.
313+
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
314+
pub enum ParamKindOrd {
315+
Lifetime,
316+
Type,
317+
Const,
318+
}
319+
320+
impl fmt::Display for ParamKindOrd {
321+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
322+
match self {
323+
ParamKindOrd::Lifetime => "lifetime".fmt(f),
324+
ParamKindOrd::Type => "type".fmt(f),
325+
ParamKindOrd::Const => "const".fmt(f),
326+
}
327+
}
328+
}
329+
310330
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
311331
pub enum GenericParamKind {
312332
/// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).

0 commit comments

Comments
 (0)