diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index b09a803e856d2..f89daf033f6cd 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -2,7 +2,9 @@ use crate::infer::InferCtxt; use crate::traits; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{ + self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, +}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{Span, DUMMY_SP}; @@ -535,305 +537,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { /// Pushes all the predicates needed to validate that `ty` is WF into `out`. #[instrument(level = "debug", skip(self))] fn compute(&mut self, arg: GenericArg<'tcx>) { - let mut walker = arg.walk(); - let param_env = self.param_env; - let depth = self.recursion_depth; - while let Some(arg) = walker.next() { - debug!(?arg, ?self.out); - let ty = match arg.unpack() { - GenericArgKind::Type(ty) => ty, - - // No WF constraints for lifetimes being present, any outlives - // obligations are handled by the parent (e.g. `ty::Ref`). - GenericArgKind::Lifetime(_) => continue, - - GenericArgKind::Const(ct) => { - match ct.kind() { - ty::ConstKind::Unevaluated(uv) => { - if !ct.has_escaping_bound_vars() { - let obligations = self.nominal_obligations(uv.def, uv.args); - self.out.extend(obligations); - - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::ConstEvaluatable(ct), - )); - let cause = self.cause(traits::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - self.recursion_depth, - self.param_env, - predicate, - )); - } - } - ty::ConstKind::Infer(_) => { - let cause = self.cause(traits::WellFormed(None)); - - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - self.recursion_depth, - self.param_env, - ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::WellFormed(ct.into()), - )), - )); - } - ty::ConstKind::Expr(_) => { - // FIXME(generic_const_exprs): this doesn't verify that given `Expr(N + 1)` the - // trait bound `typeof(N): Add` holds. This is currently unnecessary - // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` - // which means that the `DefId` would have been typeck'd elsewhere. However in - // the future we may allow directly lowering to `ConstKind::Expr` in which case - // we would not be proving bounds we should. - - let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::ConstEvaluatable(ct), - )); - let cause = self.cause(traits::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - self.recursion_depth, - self.param_env, - predicate, - )); - } - - 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 structurally-matchable. - } - } - continue; - } - }; - - debug!("wf bounds for ty={:?} ty.kind={:#?}", ty, ty.kind()); - - match *ty.kind() { - ty::Bool - | ty::Char - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Error(_) - | ty::Str - | ty::CoroutineWitness(..) - | ty::Never - | ty::Param(_) - | ty::Bound(..) - | ty::Placeholder(..) - | ty::Foreign(..) => { - // WfScalar, WfParameter, etc - } - - // Can only infer to `ty::Int(_) | ty::Uint(_)`. - ty::Infer(ty::IntVar(_)) => {} - - // Can only infer to `ty::Float(_)`. - ty::Infer(ty::FloatVar(_)) => {} - - ty::Slice(subty) => { - self.require_sized(subty, traits::SliceOrArrayElem); - } - - ty::Array(subty, _) => { - self.require_sized(subty, traits::SliceOrArrayElem); - // Note that we handle the len is implicitly checked while walking `arg`. - } - - ty::Tuple(tys) => { - if let Some((_last, rest)) = tys.split_last() { - for &elem in rest { - self.require_sized(elem, traits::TupleElem); - } - } - } - - ty::RawPtr(_) => { - // Simple cases that are WF if their type args are WF. - } - - ty::Alias(ty::Projection, data) => { - walker.skip_current_subtree(); // Subtree handled by compute_projection. - self.compute_projection(data); - } - ty::Alias(ty::Inherent, data) => { - walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection. - self.compute_inherent_projection(data); - } - - ty::Adt(def, args) => { - // WfNominalType - let obligations = self.nominal_obligations(def.did(), args); - self.out.extend(obligations); - } - - ty::FnDef(did, args) => { - let obligations = self.nominal_obligations(did, args); - self.out.extend(obligations); - } - - ty::Ref(r, rty, _) => { - // WfReference - if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { - let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - depth, - param_env, - ty::Binder::dummy(ty::PredicateKind::Clause( - ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(rty, r)), - )), - )); - } - } - - ty::Coroutine(did, args, ..) => { - // Walk ALL the types in the coroutine: this will - // include the upvar types as well as the yield - // type. Note that this is mildly distinct from - // the closure case, where we have to be careful - // about the signature of the closure. We don't - // have the problem of implied bounds here since - // coroutines don't take arguments. - let obligations = self.nominal_obligations(did, args); - self.out.extend(obligations); - } - - ty::Closure(did, args) => { - // Only check the upvar types for WF, not the rest - // of the types within. This is needed because we - // capture the signature and it may not be WF - // without the implied bounds. Consider a closure - // like `|x: &'a T|` -- it may be that `T: 'a` is - // not known to hold in the creator's context (and - // indeed the closure may not be invoked by its - // creator, but rather turned to someone who *can* - // verify that). - // - // The special treatment of closures here really - // ought not to be necessary either; the problem - // is related to #25860 -- there is no way for us - // to express a fn type complete with the implied - // bounds that it is assuming. I think in reality - // the WF rules around fn are a bit messed up, and - // that is the rot problem: `fn(&'a T)` should - // probably always be WF, because it should be - // shorthand for something like `where(T: 'a) { - // fn(&'a T) }`, as discussed in #25860. - walker.skip_current_subtree(); // subtree handled below - // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(args.as_closure().tupled_upvars_ty().into()); - // Note that we cannot skip the generic types - // types. Normally, within the fn - // body where they are created, the generics will - // always be WF, and outside of that fn body we - // are not directly inspecting closure types - // anyway, except via auto trait matching (which - // only inspects the upvar types). - // But when a closure is part of a type-alias-impl-trait - // then the function that created the defining site may - // have had more bounds available than the type alias - // specifies. This may cause us to have a closure in the - // hidden type that is not actually well formed and - // can cause compiler crashes when the user abuses unsafe - // code to procure such a closure. - // See tests/ui/type-alias-impl-trait/wf_check_closures.rs - let obligations = self.nominal_obligations(did, args); - self.out.extend(obligations); - } - - ty::CoroutineClosure(did, args) => { - // See the above comments. The same apply to coroutine-closures. - walker.skip_current_subtree(); - self.compute(args.as_coroutine_closure().tupled_upvars_ty().into()); - let obligations = self.nominal_obligations(did, args); - self.out.extend(obligations); - } - - ty::FnPtr(_) => { - // let the loop iterate into the argument/return - // types appearing in the fn signature - } - - ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { - // All of the requirements on type parameters - // have already been checked for `impl Trait` in - // return position. We do need to check type-alias-impl-trait though. - if self.tcx().is_type_alias_impl_trait(def_id) { - let obligations = self.nominal_obligations(def_id, args); - self.out.extend(obligations); - } - } - - ty::Alias(ty::Weak, ty::AliasTy { def_id, args, .. }) => { - let obligations = self.nominal_obligations(def_id, args); - self.out.extend(obligations); - } - - ty::Dynamic(data, r, _) => { - // WfObject - // - // Here, we defer WF checking due to higher-ranked - // regions. This is perhaps not ideal. - self.from_object_ty(ty, data, r); - - // FIXME(#27579) RFC also considers adding trait - // obligations that don't refer to Self and - // checking those - - let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; - - if !defer_to_coercion { - if let Some(principal) = data.principal_def_id() { - self.out.push(traits::Obligation::with_depth( - self.tcx(), - self.cause(traits::WellFormed(None)), - depth, - param_env, - ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), - )); - } - } - } - - // Inference variables are the complicated case, since we don't - // know what type they are. We do two things: - // - // 1. Check if they have been resolved, and if so proceed with - // THAT type. - // 2. If not, we've at least simplified things (e.g., we went - // from `Vec<$0>: WF` to `$0: WF`), so we can - // register a pending obligation and keep - // moving. (Goal is that an "inductive hypothesis" - // is satisfied to ensure termination.) - // See also the comment on `fn obligations`, describing "livelock" - // prevention, which happens before this can be reached. - ty::Infer(_) => { - let cause = self.cause(traits::WellFormed(None)); - self.out.push(traits::Obligation::with_depth( - self.tcx(), - cause, - self.recursion_depth, - param_env, - ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( - ty.into(), - ))), - )); - } - } - - debug!(?self.out); - } + arg.visit_with(self); + debug!(?self.out); } #[instrument(level = "debug", skip(self))] @@ -933,6 +638,302 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } } +impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { + type Result = (); + + fn visit_ty(&mut self, t: as ty::Interner>::Ty) -> Self::Result { + debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind()); + + match *t.kind() { + ty::Bool + | ty::Char + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Error(_) + | ty::Str + | ty::CoroutineWitness(..) + | ty::Never + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(..) + | ty::Foreign(..) => { + // WfScalar, WfParameter, etc + } + + // Can only infer to `ty::Int(_) | ty::Uint(_)`. + ty::Infer(ty::IntVar(_)) => {} + + // Can only infer to `ty::Float(_)`. + ty::Infer(ty::FloatVar(_)) => {} + + ty::Slice(subty) => { + self.require_sized(subty, traits::SliceOrArrayElem); + } + + ty::Array(subty, _) => { + self.require_sized(subty, traits::SliceOrArrayElem); + // Note that we handle the len is implicitly checked while walking `arg`. + } + + ty::Tuple(tys) => { + if let Some((_last, rest)) = tys.split_last() { + for &elem in rest { + self.require_sized(elem, traits::TupleElem); + } + } + } + + ty::RawPtr(_) => { + // Simple cases that are WF if their type args are WF. + } + + ty::Alias(ty::Projection, data) => { + self.compute_projection(data); + return; // Subtree handled by compute_projection. + } + ty::Alias(ty::Inherent, data) => { + self.compute_inherent_projection(data); + return; // Subtree handled by compute_inherent_projection. + } + + ty::Adt(def, args) => { + // WfNominalType + let obligations = self.nominal_obligations(def.did(), args); + self.out.extend(obligations); + } + + ty::FnDef(did, args) => { + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + } + + ty::Ref(r, rty, _) => { + // WfReference + if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() { + let cause = self.cause(traits::ReferenceOutlivesReferent(t)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives( + ty::OutlivesPredicate(rty, r), + ))), + )); + } + } + + ty::Coroutine(did, args, ..) => { + // Walk ALL the types in the coroutine: this will + // include the upvar types as well as the yield + // type. Note that this is mildly distinct from + // the closure case, where we have to be careful + // about the signature of the closure. We don't + // have the problem of implied bounds here since + // coroutines don't take arguments. + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + } + + ty::Closure(did, args) => { + // Note that we cannot skip the generic types + // types. Normally, within the fn + // body where they are created, the generics will + // always be WF, and outside of that fn body we + // are not directly inspecting closure types + // anyway, except via auto trait matching (which + // only inspects the upvar types). + // But when a closure is part of a type-alias-impl-trait + // then the function that created the defining site may + // have had more bounds available than the type alias + // specifies. This may cause us to have a closure in the + // hidden type that is not actually well formed and + // can cause compiler crashes when the user abuses unsafe + // code to procure such a closure. + // See tests/ui/type-alias-impl-trait/wf_check_closures.rs + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + // Only check the upvar types for WF, not the rest + // of the types within. This is needed because we + // capture the signature and it may not be WF + // without the implied bounds. Consider a closure + // like `|x: &'a T|` -- it may be that `T: 'a` is + // not known to hold in the creator's context (and + // indeed the closure may not be invoked by its + // creator, but rather turned to someone who *can* + // verify that). + // + // The special treatment of closures here really + // ought not to be necessary either; the problem + // is related to #25860 -- there is no way for us + // to express a fn type complete with the implied + // bounds that it is assuming. I think in reality + // the WF rules around fn are a bit messed up, and + // that is the rot problem: `fn(&'a T)` should + // probably always be WF, because it should be + // shorthand for something like `where(T: 'a) { + // fn(&'a T) }`, as discussed in #25860. + let upvars = args.as_closure().tupled_upvars_ty(); + return upvars.visit_with(self); + } + + ty::CoroutineClosure(did, args) => { + // See the above comments. The same apply to coroutine-closures. + let obligations = self.nominal_obligations(did, args); + self.out.extend(obligations); + let upvars = args.as_coroutine_closure().tupled_upvars_ty(); + return upvars.visit_with(self); + } + + ty::FnPtr(_) => { + // Let the visitor iterate into the argument/return + // types appearing in the fn signature. + } + + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { + // All of the requirements on type parameters + // have already been checked for `impl Trait` in + // return position. We do need to check type-alias-impl-trait though. + if self.tcx().is_type_alias_impl_trait(def_id) { + let obligations = self.nominal_obligations(def_id, args); + self.out.extend(obligations); + } + } + + ty::Alias(ty::Weak, ty::AliasTy { def_id, args, .. }) => { + let obligations = self.nominal_obligations(def_id, args); + self.out.extend(obligations); + } + + ty::Dynamic(data, r, _) => { + // WfObject + // + // Here, we defer WF checking due to higher-ranked + // regions. This is perhaps not ideal. + self.from_object_ty(t, data, r); + + // FIXME(#27579) RFC also considers adding trait + // obligations that don't refer to Self and + // checking those + + let defer_to_coercion = self.tcx().features().object_safe_for_dispatch; + + if !defer_to_coercion { + if let Some(principal) = data.principal_def_id() { + self.out.push(traits::Obligation::with_depth( + self.tcx(), + self.cause(traits::WellFormed(None)), + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)), + )); + } + } + } + + // Inference variables are the complicated case, since we don't + // know what type they are. We do two things: + // + // 1. Check if they have been resolved, and if so proceed with + // THAT type. + // 2. If not, we've at least simplified things (e.g., we went + // from `Vec<$0>: WF` to `$0: WF`), so we can + // register a pending obligation and keep + // moving. (Goal is that an "inductive hypothesis" + // is satisfied to ensure termination.) + // See also the comment on `fn obligations`, describing "livelock" + // prevention, which happens before this can be reached. + ty::Infer(_) => { + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + t.into(), + ))), + )); + } + } + + t.super_visit_with(self) + } + + fn visit_const(&mut self, c: as ty::Interner>::Const) -> Self::Result { + match c.kind() { + ty::ConstKind::Unevaluated(uv) => { + if !c.has_escaping_bound_vars() { + let obligations = self.nominal_obligations(uv.def, uv.args); + self.out.extend(obligations); + + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstEvaluatable(c), + )); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } + } + ty::ConstKind::Infer(_) => { + let cause = self.cause(traits::WellFormed(None)); + + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed( + c.into(), + ))), + )); + } + ty::ConstKind::Expr(_) => { + // FIXME(generic_const_exprs): this doesn't verify that given `Expr(N + 1)` the + // trait bound `typeof(N): Add` holds. This is currently unnecessary + // as `ConstKind::Expr` is only produced via normalization of `ConstKind::Unevaluated` + // which means that the `DefId` would have been typeck'd elsewhere. However in + // the future we may allow directly lowering to `ConstKind::Expr` in which case + // we would not be proving bounds we should. + + let predicate = ty::Binder::dummy(ty::PredicateKind::Clause( + ty::ClauseKind::ConstEvaluatable(c), + )); + let cause = self.cause(traits::WellFormed(None)); + self.out.push(traits::Obligation::with_depth( + self.tcx(), + cause, + self.recursion_depth, + self.param_env, + predicate, + )); + } + + 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 structurally-matchable. + } + } + + c.super_visit_with(self) + } + + fn visit_predicate(&mut self, _p: as ty::Interner>::Predicate) -> Self::Result { + bug!("predicate should not be checked for well-formedness"); + } +} + /// Given an object type like `SomeTrait + Send`, computes the lifetime /// bounds that must hold on the elided self type. These are derived /// from the declarations of `SomeTrait`, `Send`, and friends -- if diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs index 6256000b4919b..9cdb4158d2b35 100644 --- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs @@ -20,6 +20,7 @@ where //~^^^ ERROR: function takes 1 generic argument but 2 generic arguments were supplied //~^^^^ ERROR: unconstrained generic constant //~^^^^^ ERROR: unconstrained generic constant `{const expr}` + //~^^^^^^ ERROR: unconstrained generic constant `{const expr}` } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr index 6001d8247876a..14c58f8d0da7f 100644 --- a/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr +++ b/tests/ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.stderr @@ -58,7 +58,15 @@ error: unconstrained generic constant `{const expr}` LL | foo::<_, L>([(); L + 1 + L]); | ^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: unconstrained generic constant `{const expr}` + --> $DIR/issue_114151.rs:17:5 + | +LL | foo::<_, L>([(); L + 1 + L]); + | ^^^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0107, E0308. For more information about an error, try `rustc --explain E0107`.