From cb2308de549975f538bc51325481ad235cea4e9d Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 15:29:51 +0200 Subject: [PATCH 1/4] implement wf checking for constants --- src/librustc_trait_selection/traits/wf.rs | 125 +++++++++++++++------- 1 file changed, 87 insertions(+), 38 deletions(-) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 39c7528a63240..60a8881521426 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -4,7 +4,7 @@ use crate::traits; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items; -use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; use std::rc::Rc; @@ -37,7 +37,7 @@ pub fn obligations<'a, 'tcx>( }; let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(ty); + wf.compute(ty.into()); debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); let result = wf.normalize(); @@ -45,6 +45,36 @@ pub fn obligations<'a, 'tcx>( Some(result) } +/// Returns the set of obligations needed to make the `constant` well-formed. +pub fn const_obligations<'a, 'tcx>( + infcx: &InferCtxt<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + constant: &'tcx ty::Const<'tcx>, + span: Span, +) -> Option>> { + let constant = match constant.val { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } + + infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ..*constant }) + } + _ => constant, + }; + + let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; + wf.compute(constant.into()); + debug!("wf::const obligations({:?}, body_id={:?}) = {:?}", constant, body_id, wf.out); + + let result = wf.normalize(); + debug!("wf::const obligations({:?}, body_id={:?}) ~~> {:?}", constant, body_id, result); + Some(result) +} + /// Returns the obligations that make this trait reference /// well-formed. For example, if there is a trait `Set` defined like /// `trait Set`, then the trait reference `Foo: Set` is WF @@ -78,33 +108,36 @@ pub fn predicate_obligations<'a, 'tcx>( } ty::PredicateKind::RegionOutlives(..) => {} ty::PredicateKind::TypeOutlives(t) => { - wf.compute(t.skip_binder().0); + wf.compute(t.skip_binder().0.into()); } ty::PredicateKind::Projection(t) => { let t = t.skip_binder(); // (*) wf.compute_projection(t.projection_ty); - wf.compute(t.ty); + wf.compute(t.ty.into()); } &ty::PredicateKind::WellFormed(t) => { - wf.compute(t); + wf.compute(t.into()); } ty::PredicateKind::ObjectSafe(_) => {} ty::PredicateKind::ClosureKind(..) => {} ty::PredicateKind::Subtype(data) => { - wf.compute(data.skip_binder().a); // (*) - wf.compute(data.skip_binder().b); // (*) + wf.compute(data.skip_binder().a.into()); // (*) + wf.compute(data.skip_binder().b.into()); // (*) } &ty::PredicateKind::ConstEvaluatable(def_id, substs) => { let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for ty in substs.types() { - wf.compute(ty); + for subst in substs.iter().copied() { + wf.compute(subst); } } ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.ty); - wf.compute(c2.ty); + wf.compute(c1.ty.into()); + wf.compute(c2.ty.into()); + } + ty::Predicate::WellFormedConst(constant) => { + wf.compute(constant.into()); } } @@ -213,7 +246,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.infcx.tcx } - fn cause(&mut self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { + fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> { traits::ObligationCause::new(self.span, self.body_id, code) } @@ -300,22 +333,6 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } - /// Pushes the obligations required for an array length to be WF - /// into `self.out`. - fn compute_array_len(&mut self, constant: ty::Const<'tcx>) { - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = constant.val { - assert!(promoted.is_none()); - - let obligations = self.nominal_obligations(def_id, substs); - self.out.extend(obligations); - - let predicate = - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, self.param_env, predicate)); - } - } - fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) { if !subty.has_escaping_bound_vars() { let cause = self.cause(cause); @@ -332,8 +349,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } /// Pushes all the predicates needed to validate that `ty` is WF into `out`. - fn compute(&mut self, ty: Ty<'tcx>) { - let mut walker = ty.walk(); + fn compute(&mut self, arg: GenericArg<'tcx>) { + let mut walker = arg.walk(); let param_env = self.param_env; while let Some(arg) = walker.next() { let ty = match arg.unpack() { @@ -343,9 +360,43 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // obligations are handled by the parent (e.g. `ty::Ref`). GenericArgKind::Lifetime(_) => continue, - // FIXME(eddyb) this is wrong and needs to be replaced - // (see https://github.com/rust-lang/rust/pull/70107). - GenericArgKind::Const(_) => continue, + GenericArgKind::Const(constant) => { + match constant.val { + ty::ConstKind::Unevaluated(def_id, substs, promoted) => { + assert!(promoted.is_none()); + + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + predicate, + )); + } + ty::ConstKind::Infer(infer) => { + let resolved = self.infcx.shallow_resolve(infer); + // the `InferConst` changed, meaning that we made progress. + if resolved != infer { + let cause = self.cause(traits::MiscObligation); + + let resolved_constant = self.infcx.tcx.mk_const(ty::Const { + val: ty::ConstKind::Infer(resolved), + ..*constant + }); + self.out.push(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()), + )); + } + } + _ => (), + } + continue; + } }; match ty.kind { @@ -375,10 +426,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.require_sized(subty, traits::SliceOrArrayElem); } - ty::Array(subty, len) => { + ty::Array(subty, _) => { self.require_sized(subty, traits::SliceOrArrayElem); - // FIXME(eddyb) handle `GenericArgKind::Const` above instead. - self.compute_array_len(*len); } ty::Tuple(ref tys) => { @@ -467,7 +516,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { walker.skip_current_subtree(); // subtree handled below for upvar_ty in substs.as_closure().upvar_tys() { // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(upvar_ty); + self.compute(upvar_ty.into()); } } @@ -540,7 +589,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } else { // Yes, resolved, proceed with the result. // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(ty); + self.compute(ty.into()); } } } From 81831e124e002188d95d690ea090067b3653055f Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sat, 23 May 2020 18:28:50 +0200 Subject: [PATCH 2/4] add WellFormedConst predicate --- src/librustc_infer/infer/outlives/mod.rs | 3 +- src/librustc_infer/traits/util.rs | 5 ++ src/librustc_lint/builtin.rs | 1 + src/librustc_middle/ty/mod.rs | 12 +++- src/librustc_middle/ty/print/pretty.rs | 3 + src/librustc_middle/ty/structural_impls.rs | 4 ++ .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_trait_selection/opaque_types.rs | 3 +- .../traits/error_reporting/mod.rs | 18 +++++ .../traits/fulfill.rs | 15 +++++ .../traits/object_safety.rs | 6 +- src/librustc_trait_selection/traits/select.rs | 14 ++++ src/librustc_trait_selection/traits/wf.rs | 26 +++++--- src/librustc_traits/chalk/lowering.rs | 11 ++-- .../implied_outlives_bounds.rs | 3 +- .../normalize_erasing_regions.rs | 3 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 65 +++++++++++-------- .../impl_wf_check/min_specialization.rs | 3 +- src/librustc_typeck/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- .../cannot-infer-const-args.stderr | 4 +- .../ui/const-generics/issues/issue-61747.rs | 3 +- .../const-generics/issues/issue-61747.stderr | 12 +++- .../ui/const-generics/issues/issue-62220.rs | 4 +- .../const-generics/issues/issue-62220.stderr | 10 +++ .../ui/const-generics/issues/issue-66205.rs | 4 +- .../const-generics/issues/issue-66205.stderr | 11 +++- .../ui/const-generics/issues/issue-68977.rs | 40 ++++++++++++ .../const-generics/issues/issue-68977.stderr | 19 ++++++ src/test/ui/const-generics/wf-misc.rs | 16 +++++ src/test/ui/const-generics/wf-misc.stderr | 27 ++++++++ 32 files changed, 296 insertions(+), 61 deletions(-) create mode 100644 src/test/ui/const-generics/issues/issue-62220.stderr create mode 100644 src/test/ui/const-generics/issues/issue-68977.rs create mode 100644 src/test/ui/const-generics/issues/issue-68977.stderr create mode 100644 src/test/ui/const-generics/wf-misc.rs create mode 100644 src/test/ui/const-generics/wf-misc.stderr diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index fd3b38e9d67b0..ad8e44a6c1d3a 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -20,7 +20,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 8081cac0067f1..1aaa07d23cc9a 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -45,6 +45,8 @@ pub fn anonymize_predicate<'tcx>( } ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), + + ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct), }; if new != *kind { new.to_predicate(tcx) } else { pred } @@ -204,6 +206,9 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-equate // predicates. } + ty::PredicateKind::WellFormedConst(..) => { + // Currently, we do not elaborate WF predicates. + } ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index e17e8b7b9640e..bde761b01c3a0 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1218,6 +1218,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { Projection(..) | // Ignore bounds that a user can't type WellFormed(..) | + WellFormedConst(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 4cd3be932def0..554553dc6b4cf 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -1079,6 +1079,9 @@ pub enum PredicateKind<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Constant must be well formed. + WellFormedConst(&'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1195,6 +1198,9 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } + PredicateKind::WellFormedConst(c) => { + PredicateKind::WellFormedConst(c.subst(tcx, substs)) + } }; if new != *kind { new.to_predicate(tcx) } else { self } @@ -1386,7 +1392,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } @@ -1401,7 +1408,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) => None, + | PredicateKind::ConstEquate(..) + | PredicateKind::WellFormedConst(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 6a11e775c8c5a..6eb11b0c9429a 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2054,6 +2054,9 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateKind::WellFormedConst(c) => { + p!(print(c), write(" well-formed")) + } } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index c6ecb08615fcf..19a2e89ca4177 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -247,6 +247,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c), } } } @@ -507,6 +508,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } + ty::PredicateKind::WellFormedConst(c) => { + tcx.lift(&c).map(ty::PredicateKind::WellFormedConst) + } } } } diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 5615aa84eecd7..22959c6a3df2b 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -29,7 +29,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => continue, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => continue, ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index f78a6207a3ab5..8bbcfb1ade58a 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,7 +1277,8 @@ crate fn required_region_bounds( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index f8b33b782c017..1134cafbae430 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -610,6 +610,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } + ty::PredicateKind::WellFormedConst(ct) => { + // Const WF predicates cannot themselves make + // errors. They can only block due to + // ambiguity; otherwise, they always + // degenerate into other obligations + // (which may fail). + span_bug!(span, "const WF predicate not satisfied for {:?}", ct); + } + ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, @@ -1540,6 +1549,15 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) } + ty::PredicateKind::WellFormedConst(ct) => { + // Same hacky approach as above to avoid deluging user + // with error messages. + if ct.references_error() || self.tcx.sess.has_errors() { + return; + } + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } + ty::PredicateKind::Subtype(ref data) => { if data.references_error() || self.tcx.sess.has_errors() { // no need to overload user in such cases diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index c1d9b0a2d88e6..8ab81246e7d93 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -476,6 +476,21 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(predicates) => ProcessResult::Changed(mk_pending(predicates)), + None => { + pending_obligation.stalled_on = + vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()]; + ProcessResult::Unchanged + } + }, + &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index 5befc797a517a..ee7aa6b165d62 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -283,7 +283,8 @@ fn predicates_reference_self( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } }) .collect() @@ -318,7 +319,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => false, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => false, } }) } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 7aa5aa2dae89b..9dd0592c45fbb 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -450,6 +450,20 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => Ok(EvaluatedToAmbig), }, + ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + constant, + obligation.cause.span, + ) { + Some(mut obligations) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) + } + None => Ok(EvaluatedToAmbig), + }, + ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::RegionOutlives(..) => { // We do not consider region relationships when evaluating trait matches. Ok(EvaluatedToOkModuloRegions) diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 60a8881521426..458a6f5b88f22 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -128,15 +128,15 @@ pub fn predicate_obligations<'a, 'tcx>( let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for subst in substs.iter().copied() { + for subst in substs.iter() { wf.compute(subst); } } - ty::PredicateKind::ConstEquate(c1, c2) => { - wf.compute(c1.ty.into()); - wf.compute(c2.ty.into()); + &ty::PredicateKind::ConstEquate(c1, c2) => { + wf.compute(c1.into()); + wf.compute(c2.into()); } - ty::Predicate::WellFormedConst(constant) => { + &ty::PredicateKind::WellFormedConst(constant) => { wf.compute(constant.into()); } } @@ -368,7 +368,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { let obligations = self.nominal_obligations(def_id, substs); self.out.extend(obligations); - let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx()); + let predicate = ty::PredicateKind::ConstEvaluatable(def_id, substs) + .to_predicate(self.tcx()); let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( cause, @@ -389,11 +390,20 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(resolved_constant).to_predicate(self.tcx()), + ty::PredicateKind::WellFormedConst(resolved_constant) + .to_predicate(self.tcx()), )); } } - _ => (), + ty::ConstKind::Error + | ty::ConstKind::Param(_) + | ty::ConstKind::Bound(..) + | ty::ConstKind::Placeholder(..) => { + // These variants are trivially WF, so nothing to do here. + } + ty::ConstKind::Value(..) => { + // FIXME: Enforce that values are structually-matchable. + } } continue; } diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index a33ada2fb6ef1..b624598322a07 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -77,7 +77,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment chalk_ir::InEnvironment>> { let clauses = self.environment.into_iter().filter_map(|clause| match clause { ChalkEnvironmentClause::Predicate(predicate) => { - match &predicate.kind() { + match predicate.kind() { ty::PredicateKind::Trait(predicate, _) => { let (predicate, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, predicate); @@ -126,7 +126,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { bug!("unexpected predicate {}", predicate) } } @@ -193,7 +194,8 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => { + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } } @@ -460,7 +462,8 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 5dee71a2338cc..073dfe4d5920e 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -101,7 +101,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => vec![], + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => vec![], ty::PredicateKind::WellFormed(subty) => { wf_types.push(subty); diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index fcb75142269df..6a8d81085c575 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => true, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => true, } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 91562d576ea80..c17b3d78125cc 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -814,7 +814,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index a8fa65a135ac2..374ba1c73141b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3353,28 +3353,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - - // HACK(eddyb) emulate what a `WellFormedConst` obligation would do. - // This code should be replaced with the proper WF handling ASAP. - if let ty::ConstKind::Unevaluated(def_id, substs, promoted) = c.val { - assert!(promoted.is_none()); - - // HACK(eddyb) let's hope these are always empty. - // let obligations = self.nominal_obligations(def_id, substs); - // self.out.extend(obligations); - - let cause = traits::ObligationCause::new( - self.tcx.def_span(const_def_id.to_def_id()), - self.body_id, - traits::MiscObligation, - ); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateKind::ConstEvaluatable(def_id, substs).to_predicate(self.tcx), - )); - } - + self.register_wf_const_obligation( + c, + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); c } @@ -3424,11 +3407,40 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - /// Registers obligations that all types appearing in `substs` are well-formed. + /// Registers an obligation for checking later, during regionck, that the type `ty` must + /// outlive the region `r`. + pub fn register_wf_const_obligation( + &self, + ct: &'tcx ty::Const<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for ty in substs.types() { - if !ty.references_error() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + for subst in substs { + match subst.unpack() { + GenericArgKind::Lifetime(..) => { + // Nothing to do for lifetimes. + } + GenericArgKind::Type(ty) => { + if !ty.references_error() { + self.register_wf_obligation(ty, expr.span, traits::MiscObligation); + } + } + GenericArgKind::Const(ct) => { + if !ct.references_error() { + self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation); + } + } } } } @@ -3860,6 +3872,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(..) => None, ty::PredicateKind::TypeOutlives(..) => None, ty::PredicateKind::WellFormed(..) => None, + ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::ObjectSafe(..) => None, ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::ConstEquate(..) => None, diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index bf9a4d1cb6ca9..b2e8716b0380d 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => None, + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index 5740cc224cc57..cf8be687f6028 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -59,7 +59,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => (), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 371df7444b004..5c2d6c6453dbf 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,7 +491,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateKind::ConstEquate(..) + | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"), } } } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.stderr b/src/test/ui/const-generics/cannot-infer-const-args.stderr index 6696b025855a8..b29d27e524751 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.stderr +++ b/src/test/ui/const-generics/cannot-infer-const-args.stderr @@ -11,7 +11,9 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:9:5 | LL | foo(); - | ^^^ cannot infer type for fn item `fn() -> usize {foo::<{_: usize}>}` + | ^^^ + | + = note: unable to infer the value of a const parameter error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 9e0572d3568cb..cc671163e85a1 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete @@ -7,6 +5,7 @@ struct Const; impl Const<{C}> { fn successor() -> Const<{C + 1}> { + //~^ ERROR constant expression depends on a generic parameter Const } } diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr index 2e405370dc0df..2685d9fdf167c 100644 --- a/src/test/ui/const-generics/issues/issue-61747.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61747.rs:3:12 + --> $DIR/issue-61747.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,13 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-61747.rs:7:23 + | +LL | fn successor() -> Const<{C + 1}> { + | ^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index c95b306320175..5c4a0d31a895d 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,7 +1,6 @@ -// build-pass #![allow(incomplete_features)] - #![feature(const_generics)] + pub struct Vector([T; N]); pub type TruncatedVector = Vector; @@ -9,6 +8,7 @@ pub type TruncatedVector = Vector; impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { + //~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.stderr new file mode 100644 index 0000000000000..d91d2bb326fc5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62220.rs:10:27 + | +LL | pub fn trunc(self) -> (TruncatedVector, T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 76bde1815be18..7cedf51ca0404 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,6 +1,6 @@ -#![allow(incomplete_features, dead_code, unconditional_recursion)] +#![allow(dead_code, unconditional_recursion)] #![feature(const_generics)] -#![feature(lazy_normalization_consts)] +//~^ WARN the feature `const_generics` is incomplete fn fact() { fact::<{ N - 1 }>(); diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr index 416b675b56d28..1e9c0f2f3d9eb 100644 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.stderr @@ -1,3 +1,12 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-66205.rs:2:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + error: constant expression depends on a generic parameter --> $DIR/issue-66205.rs:6:12 | @@ -6,5 +15,5 @@ LL | fact::<{ N - 1 }>(); | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs new file mode 100644 index 0000000000000..346ea3c204244 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -0,0 +1,40 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +struct PhantomU8; + +trait FxpStorage { + type SInt; // Add arithmetic traits as needed. +} + +macro_rules! fxp_storage_impls { + ($($($n:literal)|+ => $sint:ty),* $(,)?) => { + $($(impl FxpStorage for PhantomU8<$n> { + type SInt = $sint; + })*)* + } +} + +fxp_storage_impls! { + 1 => i8, + 2 => i16, + 3 | 4 => i32, + 5 | 6 | 7 | 8 => i64, + 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 => i128, +} + +type FxpStorageHelper = + PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + +struct Fxp +where + FxpStorageHelper: FxpStorage, + //~^ ERROR constant expression depends on a generic parameter +{ + storage: as FxpStorage>::SInt, +} + +fn main() { + Fxp::<1, 15> { storage: 0i16 }; + Fxp::<2, 15> { storage: 0i32 }; +} diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr new file mode 100644 index 0000000000000..e1190d9026da9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-68977.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/issue-68977.rs:31:44 + | +LL | FxpStorageHelper: FxpStorage, + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs new file mode 100644 index 0000000000000..4ff1b9e2da5b2 --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.rs @@ -0,0 +1,16 @@ +#![feature(const_generics)] +//~^ WARN the feature `const_generics` is incomplete + +pub fn arr_len() { + let _: [u8; N + 1]; + //~^ ERROR constant expression depends on a generic parameter +} + +struct Const; + +pub fn func_call() { + let _: Const::<{N + 1}>; + //~^ ERROR constant expression depends on a generic parameter +} + +fn main() {} diff --git a/src/test/ui/const-generics/wf-misc.stderr b/src/test/ui/const-generics/wf-misc.stderr new file mode 100644 index 0000000000000..03f2bf3f52699 --- /dev/null +++ b/src/test/ui/const-generics/wf-misc.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/wf-misc.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:5:12 + | +LL | let _: [u8; N + 1]; + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/wf-misc.rs:12:12 + | +LL | let _: Const::<{N + 1}>; + | ^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted + From ef4d2c10430c941619ccc517e709f093a4ea9689 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 26 May 2020 23:12:01 +0200 Subject: [PATCH 3/4] change WellFormed predicate to GenericArg --- src/librustc_infer/infer/combine.rs | 2 +- src/librustc_infer/infer/outlives/mod.rs | 3 +- src/librustc_infer/traits/util.rs | 5 - src/librustc_lint/builtin.rs | 1 - src/librustc_middle/ty/mod.rs | 16 +-- src/librustc_middle/ty/print/pretty.rs | 5 +- src/librustc_middle/ty/structural_impls.rs | 6 +- .../borrow_check/type_check/mod.rs | 6 +- .../transform/qualify_min_const_fn.rs | 3 +- src/librustc_trait_selection/opaque_types.rs | 3 +- .../traits/error_reporting/mod.rs | 32 ++--- .../traits/fulfill.rs | 21 +--- .../traits/object_safety.rs | 6 +- src/librustc_trait_selection/traits/select.rs | 18 +-- src/librustc_trait_selection/traits/wf.rs | 118 +++++++++--------- src/librustc_traits/chalk/lowering.rs | 48 +++---- .../implied_outlives_bounds.rs | 15 ++- .../normalize_erasing_regions.rs | 3 +- src/librustc_traits/type_op.rs | 4 +- src/librustc_typeck/check/callee.rs | 2 +- src/librustc_typeck/check/method/confirm.rs | 2 +- src/librustc_typeck/check/method/mod.rs | 2 +- src/librustc_typeck/check/method/probe.rs | 3 +- src/librustc_typeck/check/mod.rs | 57 ++------- src/librustc_typeck/check/wfcheck.rs | 18 +-- .../impl_wf_check/min_specialization.rs | 7 +- src/librustc_typeck/outlives/explicit.rs | 3 +- src/librustdoc/clean/mod.rs | 3 +- 28 files changed, 157 insertions(+), 255 deletions(-) diff --git a/src/librustc_infer/infer/combine.rs b/src/librustc_infer/infer/combine.rs index 70a2122a9ea5d..4ef4ed47cb11a 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/src/librustc_infer/infer/combine.rs @@ -307,7 +307,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { self.obligations.push(Obligation::new( self.trace.cause.clone(), self.param_env, - ty::PredicateKind::WellFormed(b_ty).to_predicate(self.infcx.tcx), + ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx), )); } diff --git a/src/librustc_infer/infer/outlives/mod.rs b/src/librustc_infer/infer/outlives/mod.rs index ad8e44a6c1d3a..fd3b38e9d67b0 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/src/librustc_infer/infer/outlives/mod.rs @@ -20,8 +20,7 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, ty::PredicateKind::RegionOutlives(ref data) => data .no_bound_vars() .map(|ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a)), diff --git a/src/librustc_infer/traits/util.rs b/src/librustc_infer/traits/util.rs index 1aaa07d23cc9a..8081cac0067f1 100644 --- a/src/librustc_infer/traits/util.rs +++ b/src/librustc_infer/traits/util.rs @@ -45,8 +45,6 @@ pub fn anonymize_predicate<'tcx>( } ty::PredicateKind::ConstEquate(c1, c2) => ty::PredicateKind::ConstEquate(c1, c2), - - ty::PredicateKind::WellFormedConst(ct) => ty::PredicateKind::WellFormedConst(ct), }; if new != *kind { new.to_predicate(tcx) } else { pred } @@ -206,9 +204,6 @@ impl Elaborator<'tcx> { // Currently, we do not elaborate const-equate // predicates. } - ty::PredicateKind::WellFormedConst(..) => { - // Currently, we do not elaborate WF predicates. - } ty::PredicateKind::RegionOutlives(..) => { // Nothing to elaborate from `'a: 'b`. } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index bde761b01c3a0..e17e8b7b9640e 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -1218,7 +1218,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TrivialConstraints { Projection(..) | // Ignore bounds that a user can't type WellFormed(..) | - WellFormedConst(..) | ObjectSafe(..) | ClosureKind(..) | Subtype(..) | diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index 554553dc6b4cf..a34cff06bc1cd 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -14,7 +14,7 @@ use crate::mir::Body; use crate::mir::GeneratorLayout; use crate::traits::{self, Reveal}; use crate::ty; -use crate::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef}; use crate::ty::util::{Discr, IntTypeExt}; use rustc_ast::ast; use rustc_attr as attr; @@ -1061,7 +1061,7 @@ pub enum PredicateKind<'tcx> { Projection(PolyProjectionPredicate<'tcx>), /// No syntax: `T` well-formed. - WellFormed(Ty<'tcx>), + WellFormed(GenericArg<'tcx>), /// Trait must be object-safe. ObjectSafe(DefId), @@ -1079,9 +1079,6 @@ pub enum PredicateKind<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), - - /// Constant must be well formed. - WellFormedConst(&'tcx Const<'tcx>), } /// The crate outlives map is computed during typeck and contains the @@ -1198,9 +1195,6 @@ impl<'tcx> Predicate<'tcx> { PredicateKind::ConstEquate(c1, c2) => { PredicateKind::ConstEquate(c1.subst(tcx, substs), c2.subst(tcx, substs)) } - PredicateKind::WellFormedConst(c) => { - PredicateKind::WellFormedConst(c.subst(tcx, substs)) - } }; if new != *kind { new.to_predicate(tcx) } else { self } @@ -1392,8 +1386,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ClosureKind(..) | PredicateKind::TypeOutlives(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::WellFormedConst(..) => None, + | PredicateKind::ConstEquate(..) => None, } } @@ -1408,8 +1401,7 @@ impl<'tcx> Predicate<'tcx> { | PredicateKind::ObjectSafe(..) | PredicateKind::ClosureKind(..) | PredicateKind::ConstEvaluatable(..) - | PredicateKind::ConstEquate(..) - | PredicateKind::WellFormedConst(..) => None, + | PredicateKind::ConstEquate(..) => None, } } } diff --git a/src/librustc_middle/ty/print/pretty.rs b/src/librustc_middle/ty/print/pretty.rs index 6eb11b0c9429a..90fb198161793 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/src/librustc_middle/ty/print/pretty.rs @@ -2031,7 +2031,7 @@ define_print_and_forward_display! { ty::PredicateKind::RegionOutlives(predicate) => p!(print(predicate)), ty::PredicateKind::TypeOutlives(predicate) => p!(print(predicate)), ty::PredicateKind::Projection(predicate) => p!(print(predicate)), - ty::PredicateKind::WellFormed(ty) => p!(print(ty), write(" well-formed")), + ty::PredicateKind::WellFormed(arg) => p!(print(arg), write(" well-formed")), &ty::PredicateKind::ObjectSafe(trait_def_id) => { p!(write("the trait `"), print_def_path(trait_def_id, &[]), @@ -2054,9 +2054,6 @@ define_print_and_forward_display! { print(c2), write("`")) } - ty::PredicateKind::WellFormedConst(c) => { - p!(print(c), write(" well-formed")) - } } } diff --git a/src/librustc_middle/ty/structural_impls.rs b/src/librustc_middle/ty/structural_impls.rs index 19a2e89ca4177..6c1a524b7fee5 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/src/librustc_middle/ty/structural_impls.rs @@ -236,7 +236,7 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { ty::PredicateKind::RegionOutlives(ref pair) => pair.fmt(f), ty::PredicateKind::TypeOutlives(ref pair) => pair.fmt(f), ty::PredicateKind::Projection(ref pair) => pair.fmt(f), - ty::PredicateKind::WellFormed(ty) => write!(f, "WellFormed({:?})", ty), + ty::PredicateKind::WellFormed(data) => write!(f, "WellFormed({:?})", data), ty::PredicateKind::ObjectSafe(trait_def_id) => { write!(f, "ObjectSafe({:?})", trait_def_id) } @@ -247,7 +247,6 @@ impl fmt::Debug for ty::PredicateKind<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), - ty::PredicateKind::WellFormedConst(c) => write!(f, "WellFormedConst({:?})", c), } } } @@ -508,9 +507,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateKind<'a> { ty::PredicateKind::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateKind::ConstEquate(c1, c2)) } - ty::PredicateKind::WellFormedConst(c) => { - tcx.lift(&c).map(ty::PredicateKind::WellFormedConst) - } } } } diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/src/librustc_mir/borrow_check/type_check/mod.rs index fdc3b291ba44a..377a0b6f25cab 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/type_check/mod.rs @@ -1016,7 +1016,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } self.prove_predicate( - ty::PredicateKind::WellFormed(inferred_ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()), Locations::All(span), ConstraintCategory::TypeAnnotation, ); @@ -1268,7 +1268,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { obligations.obligations.push(traits::Obligation::new( ObligationCause::dummy(), param_env, - ty::PredicateKind::WellFormed(revealed_ty).to_predicate(infcx.tcx), + ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx), )); obligations.add( infcx @@ -1612,7 +1612,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.check_call_dest(body, term, &sig, destination, term_location); self.prove_predicates( - sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty)), + sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())), term_location.to_locations(), ConstraintCategory::Boring, ); diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 22959c6a3df2b..5615aa84eecd7 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -29,8 +29,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) - | ty::PredicateKind::WellFormed(_) | ty::PredicateKind::Projection(_) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => continue, + | ty::PredicateKind::ConstEquate(..) => continue, ty::PredicateKind::ObjectSafe(_) => { bug!("object safe predicate on function: {:#?}", predicate) } diff --git a/src/librustc_trait_selection/opaque_types.rs b/src/librustc_trait_selection/opaque_types.rs index 8bbcfb1ade58a..f78a6207a3ab5 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/src/librustc_trait_selection/opaque_types.rs @@ -1277,8 +1277,7 @@ crate fn required_region_bounds( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, ty::PredicateKind::TypeOutlives(predicate) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/src/librustc_trait_selection/traits/error_reporting/mod.rs index 1134cafbae430..41811bf44b1af 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/src/librustc_trait_selection/traits/error_reporting/mod.rs @@ -19,6 +19,7 @@ use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; +use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -610,15 +611,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } - ty::PredicateKind::WellFormedConst(ct) => { - // Const WF predicates cannot themselves make - // errors. They can only block due to - // ambiguity; otherwise, they always - // degenerate into other obligations - // (which may fail). - span_bug!(span, "const WF predicate not satisfied for {:?}", ct); - } - ty::PredicateKind::ConstEvaluatable(..) => { // Errors for `ConstEvaluatable` predicates show up as // `SelectionError::ConstEvalFailure`, @@ -1540,22 +1532,24 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { err } - ty::PredicateKind::WellFormed(ty) => { + ty::PredicateKind::WellFormed(arg) => { // Same hacky approach as above to avoid deluging user // with error messages. - if ty.references_error() || self.tcx.sess.has_errors() { + if arg.references_error() || self.tcx.sess.has_errors() { return; } - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - ty::PredicateKind::WellFormedConst(ct) => { - // Same hacky approach as above to avoid deluging user - // with error messages. - if ct.references_error() || self.tcx.sess.has_errors() { - return; + match arg.unpack() { + GenericArgKind::Lifetime(lt) => { + span_bug!(span, "unexpected well formed predicate: {:?}", lt) + } + GenericArgKind::Type(ty) => { + self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) + } + GenericArgKind::Const(ct) => { + self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) + } } - self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) } ty::PredicateKind::Subtype(ref data) => { diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/src/librustc_trait_selection/traits/fulfill.rs index 8ab81246e7d93..51c62dbb88c84 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/src/librustc_trait_selection/traits/fulfill.rs @@ -459,38 +459,23 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } - &ty::PredicateKind::WellFormed(ty) => { + &ty::PredicateKind::WellFormed(arg) => { match wf::obligations( self.selcx.infcx(), obligation.param_env, obligation.cause.body_id, - ty, + arg, obligation.cause.span, ) { None => { pending_obligation.stalled_on = - vec![TyOrConstInferVar::maybe_from_ty(ty).unwrap()]; + vec![TyOrConstInferVar::maybe_from_generic_arg(arg).unwrap()]; ProcessResult::Unchanged } Some(os) => ProcessResult::Changed(mk_pending(os)), } } - ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( - self.selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - constant, - obligation.cause.span, - ) { - Some(predicates) => ProcessResult::Changed(mk_pending(predicates)), - None => { - pending_obligation.stalled_on = - vec![TyOrConstInferVar::maybe_from_const(constant).unwrap()]; - ProcessResult::Unchanged - } - }, - &ty::PredicateKind::Subtype(subtype) => { match self.selcx.infcx().subtype_predicate( &obligation.cause, diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/src/librustc_trait_selection/traits/object_safety.rs index ee7aa6b165d62..5befc797a517a 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/src/librustc_trait_selection/traits/object_safety.rs @@ -283,8 +283,7 @@ fn predicates_reference_self( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, } }) .collect() @@ -319,8 +318,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => false, + | ty::PredicateKind::ConstEquate(..) => false, } }) } diff --git a/src/librustc_trait_selection/traits/select.rs b/src/librustc_trait_selection/traits/select.rs index 9dd0592c45fbb..517433b90ee12 100644 --- a/src/librustc_trait_selection/traits/select.rs +++ b/src/librustc_trait_selection/traits/select.rs @@ -436,25 +436,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - &ty::PredicateKind::WellFormed(ty) => match wf::obligations( + &ty::PredicateKind::WellFormed(arg) => match wf::obligations( self.infcx, obligation.param_env, obligation.cause.body_id, - ty, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) - } - None => Ok(EvaluatedToAmbig), - }, - - ty::PredicateKind::WellFormedConst(constant) => match wf::const_obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - constant, + arg, obligation.cause.span, ) { Some(mut obligations) => { diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index 458a6f5b88f22..dde50a849527d 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -9,9 +9,9 @@ use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstnes use rustc_span::Span; use std::rc::Rc; -/// Returns the set of obligations needed to make `ty` well-formed. -/// If `ty` contains unresolved inference variables, this may include -/// further WF obligations. However, if `ty` IS an unresolved +/// Returns the set of obligations needed to make `arg` well-formed. +/// If `arg` contains unresolved inference variables, this may include +/// further WF obligations. However, if `arg` IS an unresolved /// inference variable, returns `None`, because we are not able to /// make any progress at all. This is to prevent "livelock" where we /// say "$0 is WF if $0 is WF". @@ -19,59 +19,51 @@ pub fn obligations<'a, 'tcx>( infcx: &InferCtxt<'a, 'tcx>, param_env: ty::ParamEnv<'tcx>, body_id: hir::HirId, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, span: Span, ) -> Option>> { // Handle the "livelock" case (see comment above) by bailing out if necessary. - let ty = match ty.kind { - ty::Infer(ty::TyVar(_)) => { - let resolved_ty = infcx.shallow_resolve(ty); - if resolved_ty == ty { - // No progress, bail out to prevent "livelock". - return None; - } + let arg = match arg.unpack() { + GenericArgKind::Type(ty) => { + match ty.kind { + ty::Infer(ty::TyVar(_)) => { + let resolved_ty = infcx.shallow_resolve(ty); + if resolved_ty == ty { + // No progress, bail out to prevent "livelock". + return None; + } - resolved_ty + resolved_ty + } + _ => ty, + } + .into() } - _ => ty, - }; - - let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(ty.into()); - debug!("wf::obligations({:?}, body_id={:?}) = {:?}", ty, body_id, wf.out); - - let result = wf.normalize(); - debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", ty, body_id, result); - Some(result) -} + GenericArgKind::Const(ct) => { + match ct.val { + ty::ConstKind::Infer(infer) => { + let resolved = infcx.shallow_resolve(infer); + if resolved == infer { + // No progress. + return None; + } -/// Returns the set of obligations needed to make the `constant` well-formed. -pub fn const_obligations<'a, 'tcx>( - infcx: &InferCtxt<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - constant: &'tcx ty::Const<'tcx>, - span: Span, -) -> Option>> { - let constant = match constant.val { - ty::ConstKind::Infer(infer) => { - let resolved = infcx.shallow_resolve(infer); - if resolved == infer { - // No progress. - return None; + infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty }) + } + _ => ct, } - - infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ..*constant }) + .into() } - _ => constant, + // There is nothing we have to do for lifetimes. + GenericArgKind::Lifetime(..) => return Some(Vec::new()), }; let mut wf = WfPredicates { infcx, param_env, body_id, span, out: vec![], item: None }; - wf.compute(constant.into()); - debug!("wf::const obligations({:?}, body_id={:?}) = {:?}", constant, body_id, wf.out); + wf.compute(arg); + debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out); let result = wf.normalize(); - debug!("wf::const obligations({:?}, body_id={:?}) ~~> {:?}", constant, body_id, result); + debug!("wf::obligations({:?}, body_id={:?}) ~~> {:?}", arg, body_id, result); Some(result) } @@ -115,8 +107,8 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute_projection(t.projection_ty); wf.compute(t.ty.into()); } - &ty::PredicateKind::WellFormed(t) => { - wf.compute(t.into()); + &ty::PredicateKind::WellFormed(arg) => { + wf.compute(arg); } ty::PredicateKind::ObjectSafe(_) => {} ty::PredicateKind::ClosureKind(..) => {} @@ -128,17 +120,14 @@ pub fn predicate_obligations<'a, 'tcx>( let obligations = wf.nominal_obligations(def_id, substs); wf.out.extend(obligations); - for subst in substs.iter() { - wf.compute(subst); + for arg in substs.iter() { + wf.compute(arg); } } &ty::PredicateKind::ConstEquate(c1, c2) => { wf.compute(c1.into()); wf.compute(c2.into()); } - &ty::PredicateKind::WellFormedConst(constant) => { - wf.compute(constant.into()); - } } wf.normalize() @@ -306,15 +295,22 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } let tcx = self.tcx(); - self.out.extend(trait_ref.substs.types().filter(|ty| !ty.has_escaping_bound_vars()).map( - |ty| { - traits::Obligation::new( - cause.clone(), - param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(tcx), - ) - }, - )); + self.out.extend( + trait_ref + .substs + .iter() + .filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) + .filter(|arg| !arg.has_escaping_bound_vars()) + .map(|arg| { + traits::Obligation::new( + cause.clone(), + param_env, + ty::PredicateKind::WellFormed(arg).to_predicate(tcx), + ) + }), + ); } /// Pushes the obligations required for `trait_ref::Item` to be WF @@ -390,7 +386,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(resolved_constant) + ty::PredicateKind::WellFormed(resolved_constant.into()) .to_predicate(self.tcx()), )); } @@ -594,7 +590,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { self.out.push(traits::Obligation::new( cause, param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()), )); } else { // Yes, resolved, proceed with the result. diff --git a/src/librustc_traits/chalk/lowering.rs b/src/librustc_traits/chalk/lowering.rs index b624598322a07..9530b07e47cdb 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/src/librustc_traits/chalk/lowering.rs @@ -36,7 +36,7 @@ use rustc_middle::traits::{ ChalkRustInterner as RustInterner, }; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::subst::{GenericArg, SubstsRef}; +use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ self, Binder, BoundRegion, Region, RegionKind, Ty, TyCtxt, TyKind, TypeFoldable, TypeVisitor, }; @@ -126,8 +126,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment { + | ty::PredicateKind::ConstEquate(..) => { bug!("unexpected predicate {}", predicate) } } @@ -166,24 +165,31 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } ty::PredicateKind::Projection(predicate) => predicate.lower_into(interner), - ty::PredicateKind::WellFormed(ty) => match ty.kind { - // These types are always WF. - ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) - } + ty::PredicateKind::WellFormed(arg) => match arg.unpack() { + GenericArgKind::Type(ty) => match ty.kind { + // These types are always WF. + ty::Str | ty::Placeholder(..) | ty::Error | ty::Never => { + chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + } - // FIXME(chalk): Well-formed only if ref lifetime outlives type - ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), + // FIXME(chalk): Well-formed only if ref lifetime outlives type + ty::Ref(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), - ty::Param(..) => panic!("No Params expected."), + ty::Param(..) => panic!("No Params expected."), - // FIXME(chalk) -- ultimately I think this is what we - // want to do, and we just have rules for how to prove - // `WellFormed` for everything above, instead of - // inlining a bit the rules of the proof here. - _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - )), + // FIXME(chalk) -- ultimately I think this is what we + // want to do, and we just have rules for how to prove + // `WellFormed` for everything above, instead of + // inlining a bit the rules of the proof here. + _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + )), + }, + // FIXME(chalk): handle well formed consts + GenericArgKind::Const(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + } + GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), }, // FIXME(chalk): other predicates @@ -194,8 +200,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => { + | ty::PredicateKind::ConstEquate(..) => { chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) } } @@ -462,8 +467,7 @@ impl<'tcx> LowerInto<'tcx, Option bug!("unexpected predicate {}", &self), + | ty::PredicateKind::ConstEquate(..) => bug!("unexpected predicate {}", &self), } } } diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/src/librustc_traits/implied_outlives_bounds.rs index 073dfe4d5920e..651596d0379bb 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/src/librustc_traits/implied_outlives_bounds.rs @@ -47,14 +47,14 @@ fn compute_implied_outlives_bounds<'tcx>( // process it next. Currently (at least) these resulting // predicates are always guaranteed to be a subset of the original // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; + let mut wf_args = vec![ty.into()]; let mut implied_bounds = vec![]; let mut fulfill_cx = FulfillmentContext::new(); - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is + while let Some(arg) = wf_args.pop() { + // Compute the obligations for `arg` to be well-formed. If `arg` is // an unresolved inference variable, just substituted an empty set // -- because the return type here is going to be things we *add* // to the environment, it's always ok for this set to be smaller @@ -62,7 +62,7 @@ fn compute_implied_outlives_bounds<'tcx>( // unresolved inference variables here anyway, but there might be // during typeck under some circumstances.) let obligations = - wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, ty, DUMMY_SP).unwrap_or(vec![]); + wf::obligations(infcx, param_env, hir::CRATE_HIR_ID, arg, DUMMY_SP).unwrap_or(vec![]); // N.B., all of these predicates *ought* to be easily proven // true. In fact, their correctness is (mostly) implied by @@ -101,11 +101,10 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => vec![], + | ty::PredicateKind::ConstEquate(..) => vec![], - ty::PredicateKind::WellFormed(subty) => { - wf_types.push(subty); + &ty::PredicateKind::WellFormed(arg) => { + wf_args.push(arg); vec![] } diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/src/librustc_traits/normalize_erasing_regions.rs index 6a8d81085c575..fcb75142269df 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/src/librustc_traits/normalize_erasing_regions.rs @@ -49,7 +49,6 @@ fn not_outlives_predicate(p: &ty::Predicate<'_>) -> bool { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => true, + | ty::PredicateKind::ConstEquate(..) => true, } } diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index 22077b49c3b77..374ef3fc9c783 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -140,7 +140,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { self.relate(self_ty, Variance::Invariant, impl_self_ty)?; self.prove_predicate( - ty::PredicateKind::WellFormed(impl_self_ty).to_predicate(self.tcx()), + ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()), ); } @@ -155,7 +155,7 @@ impl AscribeUserTypeCx<'me, 'tcx> { // them? This would only be relevant if some input // type were ill-formed but did not appear in `ty`, // which...could happen with normalization... - self.prove_predicate(ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx())); + self.prove_predicate(ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx())); Ok(()) } } diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index f4e46a0493151..aa316105f7f11 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -94,7 +94,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; // we must check that return type of called functions is WF: - self.register_wf_obligation(output, call_expr.span, traits::MiscObligation); + self.register_wf_obligation(output.into(), call_expr.span, traits::MiscObligation); output } diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs index 48d27387476a2..007794ce1b7ff 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/src/librustc_typeck/check/method/confirm.rs @@ -413,7 +413,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // the function type must also be well-formed (this is not // implied by the substs being well-formed because of inherent // impls and late-bound regions - see issue #28609). - self.register_wf_obligation(fty, self.span, traits::MiscObligation); + self.register_wf_obligation(fty.into(), self.span, traits::MiscObligation); } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index aae02ea0273f9..ac3fa15417e9c 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { obligations.push(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormed(method_ty).to_predicate(tcx), + ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx), )); let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig }; diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index c17b3d78125cc..91562d576ea80 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -814,8 +814,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::TypeOutlives(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 374ba1c73141b..275581318f75d 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -121,9 +121,8 @@ use rustc_middle::ty::adjustment::{ }; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{ - GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, -}; +use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; use rustc_middle::ty::{ self, AdtKind, CanonicalUserType, Const, GenericParamDefKind, RegionKind, ToPolyTraitRef, @@ -3333,7 +3332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { let t = AstConv::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t, ast_t.span, traits::MiscObligation); + self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); t } @@ -3353,8 +3352,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_const_obligation( - c, + self.register_wf_obligation( + c.into(), self.tcx.hir().span(ast_c.hir_id), ObligationCauseCode::MiscObligation, ); @@ -3394,24 +3393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// outlive the region `r`. pub fn register_wf_obligation( &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - // WF obligations never themselves fail, so no real need to give a detailed cause: - let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateKind::WellFormed(ty).to_predicate(self.tcx), - )); - } - - /// Registers an obligation for checking later, during regionck, that the type `ty` must - /// outlive the region `r`. - pub fn register_wf_const_obligation( - &self, - ct: &'tcx ty::Const<'tcx>, + arg: subst::GenericArg<'tcx>, span: Span, code: traits::ObligationCauseCode<'tcx>, ) { @@ -3420,28 +3402,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_predicate(traits::Obligation::new( cause, self.param_env, - ty::PredicateKind::WellFormedConst(ct).to_predicate(self.tcx), + ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx), )); } /// Registers obligations that all `substs` are well-formed. pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for subst in substs { - match subst.unpack() { - GenericArgKind::Lifetime(..) => { - // Nothing to do for lifetimes. - } - GenericArgKind::Type(ty) => { - if !ty.references_error() { - self.register_wf_obligation(ty, expr.span, traits::MiscObligation); - } - } - GenericArgKind::Const(ct) => { - if !ct.references_error() { - self.register_wf_const_obligation(ct, expr.span, traits::MiscObligation); - } - } - } + for arg in substs.iter().filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) { + self.register_wf_obligation(arg, expr.span, traits::MiscObligation); } } @@ -3872,7 +3842,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::PredicateKind::RegionOutlives(..) => None, ty::PredicateKind::TypeOutlives(..) => None, ty::PredicateKind::WellFormed(..) => None, - ty::PredicateKind::WellFormedConst(..) => None, ty::PredicateKind::ObjectSafe(..) => None, ty::PredicateKind::ConstEvaluatable(..) => None, ty::PredicateKind::ConstEquate(..) => None, @@ -3914,8 +3883,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // All the input types from the fn signature must outlive the call // so as to validate implied bounds. - for (fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { - self.register_wf_obligation(fn_input_ty, arg_expr.span, traits::MiscObligation); + for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { + self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); } let expected_arg_count = fn_inputs.len(); diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index e154184f1822c..7d9bf975c6913 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -292,7 +292,7 @@ fn check_associated_item( ty::AssocKind::Const => { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); - fcx.register_wf_obligation(ty, span, code.clone()); + fcx.register_wf_obligation(ty.into(), span, code.clone()); } ty::AssocKind::Fn => { let sig = fcx.tcx.fn_sig(item.def_id); @@ -313,7 +313,7 @@ fn check_associated_item( if item.defaultness.has_value() { let ty = fcx.tcx.type_of(item.def_id); let ty = fcx.normalize_associated_types_in(span, &ty); - fcx.register_wf_obligation(ty, span, code.clone()); + fcx.register_wf_obligation(ty.into(), span, code.clone()); } } ty::AssocKind::OpaqueTy => { @@ -406,7 +406,7 @@ fn check_type_defn<'tcx, F>( // All field types must be well-formed. for field in &variant.fields { fcx.register_wf_obligation( - field.ty, + field.ty.into(), field.span, ObligationCauseCode::MiscObligation, ) @@ -601,7 +601,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo } } - fcx.register_wf_obligation(item_ty, ty_span, ObligationCauseCode::MiscObligation); + fcx.register_wf_obligation(item_ty.into(), ty_span, ObligationCauseCode::MiscObligation); if forbid_unsized { fcx.register_bound( item_ty, @@ -650,7 +650,7 @@ fn check_impl<'tcx>( let self_ty = fcx.tcx.type_of(item_def_id); let self_ty = fcx.normalize_associated_types_in(item.span, &self_ty); fcx.register_wf_obligation( - self_ty, + self_ty.into(), ast_self_ty.span, ObligationCauseCode::MiscObligation, ); @@ -698,7 +698,7 @@ fn check_where_clauses<'tcx, 'fcx>( // be sure if it will error or not as user might always specify the other. if !ty.needs_subst() { fcx.register_wf_obligation( - ty, + ty.into(), fcx.tcx.def_span(param.def_id), ObligationCauseCode::MiscObligation, ); @@ -841,13 +841,13 @@ fn check_fn_or_method<'fcx, 'tcx>( let sig = fcx.normalize_associated_types_in(span, &sig); let sig = fcx.tcx.liberate_late_bound_regions(def_id, &sig); - for (input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) { - fcx.register_wf_obligation(&input_ty, span, ObligationCauseCode::MiscObligation); + for (&input_ty, span) in sig.inputs().iter().zip(hir_sig.decl.inputs.iter().map(|t| t.span)) { + fcx.register_wf_obligation(input_ty.into(), span, ObligationCauseCode::MiscObligation); } implied_bounds.extend(sig.inputs()); fcx.register_wf_obligation( - sig.output(), + sig.output().into(), hir_sig.decl.output.span(), ObligationCauseCode::ReturnType, ); diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/src/librustc_typeck/impl_wf_check/min_specialization.rs index b2e8716b0380d..e4bffedd620b9 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/src/librustc_typeck/impl_wf_check/min_specialization.rs @@ -332,12 +332,12 @@ fn check_predicates<'tcx>( }); // Include the well-formed predicates of the type parameters of the impl. - for ty in tcx.impl_trait_ref(impl1_def_id).unwrap().substs.types() { + for arg in tcx.impl_trait_ref(impl1_def_id).unwrap().substs { if let Some(obligations) = wf::obligations( infcx, tcx.param_env(impl1_def_id), tcx.hir().as_local_hir_id(impl1_def_id), - ty, + arg, span, ) { impl2_predicates @@ -405,7 +405,6 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateKind::ObjectSafe(_) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => None, + | ty::PredicateKind::ConstEquate(..) => None, } } diff --git a/src/librustc_typeck/outlives/explicit.rs b/src/librustc_typeck/outlives/explicit.rs index cf8be687f6028..5740cc224cc57 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/src/librustc_typeck/outlives/explicit.rs @@ -59,8 +59,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::Subtype(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => (), + | ty::PredicateKind::ConstEquate(..) => (), } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5c2d6c6453dbf..371df7444b004 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -491,8 +491,7 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateKind::ObjectSafe(..) | ty::PredicateKind::ClosureKind(..) | ty::PredicateKind::ConstEvaluatable(..) - | ty::PredicateKind::ConstEquate(..) - | ty::PredicateKind::WellFormedConst(..) => panic!("not user writable"), + | ty::PredicateKind::ConstEquate(..) => panic!("not user writable"), } } } From 631ac9c472322077304d9acc4de21220c54c56db Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Tue, 26 May 2020 23:13:18 +0200 Subject: [PATCH 4/4] update tests --- src/librustc_trait_selection/traits/wf.rs | 7 ++++--- src/librustc_typeck/check/mod.rs | 3 +-- .../ui/const-generics/issues/issue-61935.rs | 3 +-- .../const-generics/issues/issue-61935.stderr | 12 ++++++++++-- .../lazy-normalization/issue-71922.rs | 4 ++-- .../lazy-normalization/issue-71922.stderr | 19 +++++++++++++++++++ 6 files changed, 37 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/const-generics/lazy-normalization/issue-71922.stderr diff --git a/src/librustc_trait_selection/traits/wf.rs b/src/librustc_trait_selection/traits/wf.rs index dde50a849527d..5024392a0f98d 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/src/librustc_trait_selection/traits/wf.rs @@ -398,7 +398,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // These variants are trivially WF, so nothing to do here. } ty::ConstKind::Value(..) => { - // FIXME: Enforce that values are structually-matchable. + // FIXME: Enforce that values are structurally-matchable. } } continue; @@ -434,6 +434,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { ty::Array(subty, _) => { self.require_sized(subty, traits::SliceOrArrayElem); + // Note that we handle the len is implicitly checked while walking `arg`. } ty::Tuple(ref tys) => { @@ -445,11 +446,11 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } ty::RawPtr(_) => { - // simple cases that are WF if their type args are WF + // Simple cases that are WF if their type args are WF. } ty::Projection(data) => { - walker.skip_current_subtree(); // subtree handled by compute_projection + walker.skip_current_subtree(); // Subtree handled by compute_projection. self.compute_projection(data); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 275581318f75d..ba4bca8cd9981 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3389,8 +3389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - /// Registers an obligation for checking later, during regionck, that the type `ty` must - /// outlive the region `r`. + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. pub fn register_wf_obligation( &self, arg: subst::GenericArg<'tcx>, diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 5c987e63a9e07..0d42ff1895cdb 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,5 +1,3 @@ -// check-pass - #![feature(const_generics)] //~^ WARN the feature `const_generics` is incomplete @@ -8,6 +6,7 @@ trait Foo {} impl Foo for [(); N] where Self:FooImpl<{N==0}> +//~^ERROR constant expression depends on a generic parameter {} trait FooImpl{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr index cf0c0e24a7604..a785af5f008ea 100644 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ b/src/test/ui/const-generics/issues/issue-61935.stderr @@ -1,5 +1,5 @@ warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:3:12 + --> $DIR/issue-61935.rs:1:12 | LL | #![feature(const_generics)] | ^^^^^^^^^^^^^^ @@ -7,5 +7,13 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -warning: 1 warning emitted +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:8:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs index 36513f94a9e97..0d392ddcaedcc 100644 --- a/src/test/ui/const-generics/lazy-normalization/issue-71922.rs +++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.rs @@ -1,9 +1,9 @@ -// run-pass #![feature(const_generics)] -#![allow(incomplete_features)] +//~^ WARN the feature `const_generics` is incomplete trait Foo {} impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} +//~^ ERROR constant expression depends on a generic parameter trait FooImpl {} diff --git a/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr new file mode 100644 index 0000000000000..00917571e716d --- /dev/null +++ b/src/test/ui/const-generics/lazy-normalization/issue-71922.stderr @@ -0,0 +1,19 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-71922.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/issue-71922.rs:5:50 + | +LL | impl Foo for [(); N] where Self: FooImpl<{ N == 0 }> {} + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error; 1 warning emitted +