diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index ed3da31fb89bd..8d51fbc174a04 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -550,17 +550,32 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { let opt_ty = self.substs.get(p.idx as usize).map(|k| k.unpack()); let ty = match opt_ty { Some(UnpackedKind::Type(ty)) => ty, - _ => { + Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, - "Type parameter `{:?}` ({:?}/{}) out of range \ + "expected type for `{:?}` ({:?}/{}) but found {:?} \ when substituting (root type={:?}) substs={:?}", p, source_ty, p.idx, + kind, self.root_ty, - self.substs); + self.substs, + ); + } + None => { + let span = self.span.unwrap_or(DUMMY_SP); + span_bug!( + span, + "type parameter `{:?}` ({:?}/{}) out of range \ + when substituting (root type={:?}) substs={:?}", + p, + source_ty, + p.idx, + self.root_ty, + self.substs, + ); } }; @@ -570,29 +585,41 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { fn const_for_param( &self, p: ParamConst, - source_cn: &'tcx ty::Const<'tcx> + source_ct: &'tcx ty::Const<'tcx> ) -> &'tcx ty::Const<'tcx> { // Look up the const in the substitutions. It really should be in there. - let opt_cn = self.substs.get(p.index as usize).map(|k| k.unpack()); - let cn = match opt_cn { - Some(UnpackedKind::Const(cn)) => cn, - _ => { + let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack()); + let ct = match opt_ct { + Some(UnpackedKind::Const(ct)) => ct, + Some(kind) => { let span = self.span.unwrap_or(DUMMY_SP); span_bug!( span, - "Const parameter `{:?}` ({:?}/{}) out of range \ - when substituting (root type={:?}) substs={:?}", + "expected const for `{:?}` ({:?}/{}) but found {:?} \ + when substituting substs={:?}", p, - source_cn, + source_ct, + p.index, + kind, + self.substs, + ); + } + None => { + let span = self.span.unwrap_or(DUMMY_SP); + span_bug!( + span, + "const parameter `{:?}` ({:?}/{}) out of range \ + when substituting substs={:?}", + p, + source_ct, p.index, - self.root_ty, self.substs, ); } }; // FIXME(const_generics): shift const through binders - cn + ct } /// It is sometimes necessary to adjust the De Bruijn indices during substitution. This occurs diff --git a/src/librustc_passes/ast_validation.rs b/src/librustc_passes/ast_validation.rs index 1f5a6d7914125..6cb3161382af2 100644 --- a/src/librustc_passes/ast_validation.rs +++ b/src/librustc_passes/ast_validation.rs @@ -21,7 +21,7 @@ use syntax::visit::{self, Visitor}; use syntax::{span_err, struct_span_err, walk_list}; use syntax_ext::proc_macro_decls::is_proc_macro_attr; use syntax_pos::{Span, MultiSpan}; -use errors::Applicability; +use errors::{Applicability, FatalError}; use log::debug; #[derive(Copy, Clone, Debug)] @@ -368,6 +368,8 @@ fn validate_generics_order<'a>( let mut max_param: Option = None; let mut out_of_order = FxHashMap::default(); let mut param_idents = vec![]; + let mut found_type = false; + let mut found_const = false; for (kind, bounds, span, ident) in generics { if let Some(ident) = ident { @@ -381,6 +383,11 @@ fn validate_generics_order<'a>( } Some(_) | None => *max_param = Some(kind), }; + match kind { + ParamKindOrd::Type => found_type = true, + ParamKindOrd::Const => found_const = true, + _ => {} + } } let mut ordered_params = "<".to_string(); @@ -408,8 +415,8 @@ fn validate_generics_order<'a>( GenericPosition::Arg => "argument", }; - for (param_ord, (max_param, spans)) in out_of_order { - let mut err = handler.struct_span_err(spans, + for (param_ord, (max_param, spans)) in &out_of_order { + let mut err = handler.struct_span_err(spans.clone(), &format!( "{} {pos}s must be declared prior to {} {pos}s", param_ord, @@ -430,6 +437,13 @@ fn validate_generics_order<'a>( } err.emit(); } + + // FIXME(const_generics): we shouldn't have to abort here at all, but we currently get ICEs + // if we don't. Const parameters and type parameters can currently conflict if they + // are out-of-order. + if !out_of_order.is_empty() && found_type && found_const { + FatalError.raise(); + } } impl<'a> Visitor<'a> for AstValidator<'a> { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 4932d77ef0477..16033c6c50fd0 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -553,7 +553,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { tcx.intern_substs(&substs) } - /// Given the type/region arguments provided to some path (along with + /// Given the type/lifetime/const arguments provided to some path (along with /// an implicit `Self`, if this is a trait reference) returns the complete /// set of substitutions. This may involve applying defaulted type parameters. /// @@ -678,7 +678,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx> + 'o { GenericParamDefKind::Const => { // FIXME(const_generics:defaults) // We've already errored above about the mismatch. - tcx.types.err.into() + tcx.consts.err.into() } } }, diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 8ee30c0d2d31d..1420c66c73ea3 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -421,8 +421,8 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( return_ty: Option>, ) { let predicates = fcx.tcx.predicates_of(def_id); - let generics = tcx.generics_of(def_id); + let is_our_default = |def: &ty::GenericParamDef| { match def.kind { GenericParamDefKind::Type { has_default, .. } => { @@ -465,6 +465,7 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // All regions are identity. fcx.tcx.mk_param_from_def(param) } + GenericParamDefKind::Type { .. } => { // If the param has a default, if is_our_default(param) { @@ -478,25 +479,24 @@ fn check_where_clauses<'a, 'gcx, 'fcx, 'tcx>( // Mark unwanted params as err. fcx.tcx.types.err.into() } + GenericParamDefKind::Const => { // FIXME(const_generics:defaults) - fcx.tcx.types.err.into() + fcx.tcx.consts.err.into() } } }); + // Now we build the substituted predicates. let default_obligations = predicates.predicates.iter().flat_map(|&(pred, _)| { #[derive(Default)] struct CountParams { params: FxHashSet } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.sty { - ty::Param(p) => { - self.params.insert(p.idx); - t.super_visit_with(self) - } - _ => t.super_visit_with(self) + if let ty::Param(param) = t.sty { + self.params.insert(param.idx); } + t.super_visit_with(self) } fn visit_region(&mut self, _: ty::Region<'tcx>) -> bool { diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 188b5dce31ea8..2c81681b85e7d 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,12 +1,12 @@ #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash -fn foo(_: &T) { - //~^ ERROR type parameters must be declared prior to const parameters -} - fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters } +fn foo(_: &T) { + //~^ ERROR type parameters must be declared prior to const parameters +} + fn main() {} diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.stderr index 78f129e79ea24..33f981d1eba9b 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.stderr @@ -4,17 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ -error: type parameters must be declared prior to const parameters +error: lifetime parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:4:21 | -LL | fn foo(_: &T) { - | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` +LL | fn bar(_: &'a ()) { + | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` -error: lifetime parameters must be declared prior to const parameters +error: type parameters must be declared prior to const parameters --> $DIR/const-param-before-other-params.rs:8:21 | -LL | fn bar(_: &'a ()) { - | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` +LL | fn foo(_: &T) { + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.rs b/src/test/ui/const-generics/const-param-in-trait-ungated.rs new file mode 100644 index 0000000000000..8a81bcc1a80c8 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.rs @@ -0,0 +1,3 @@ +trait Trait {} //~ ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr new file mode 100644 index 0000000000000..53bc973841416 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/const-param-in-trait-ungated.rs:1:19 + | +LL | trait Trait {} + | ^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/44580 + = help: add #![feature(const_generics)] to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/const-param-in-trait.rs b/src/test/ui/const-generics/const-param-in-trait.rs new file mode 100644 index 0000000000000..6e4f65fe6cac0 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.rs @@ -0,0 +1,8 @@ +// run-pass + +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete and may cause the compiler to crash + +trait Trait {} + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait.stderr b/src/test/ui/const-generics/const-param-in-trait.stderr new file mode 100644 index 0000000000000..a48eefddaa844 --- /dev/null +++ b/src/test/ui/const-generics/const-param-in-trait.stderr @@ -0,0 +1,6 @@ +warning: the feature `const_generics` is incomplete and may cause the compiler to crash + --> $DIR/const-param-in-trait.rs:3:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ +