From 7c8887ccbf7104e98ead7539f3cfbd42332b5e4d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 23 Oct 2018 20:31:57 -0400 Subject: [PATCH 1/2] introduce (but do not use) `ascribe_user_type` goal Lots of annoying boilerplate. --- src/librustc/dep_graph/dep_node.rs | 6 +- src/librustc/mir/mod.rs | 8 ++ src/librustc/traits/query/mod.rs | 3 + .../traits/query/type_op/ascribe_user_type.rs | 74 +++++++++++++++++++ src/librustc/traits/query/type_op/mod.rs | 1 + src/librustc/ty/mod.rs | 2 +- src/librustc/ty/query/config.rs | 14 +++- src/librustc/ty/query/mod.rs | 17 ++++- src/librustc/ty/query/plumbing.rs | 1 + .../borrow_check/nll/type_check/mod.rs | 1 + src/librustc_traits/type_op.rs | 14 ++++ 11 files changed, 133 insertions(+), 8 deletions(-) create mode 100644 src/librustc/traits/query/type_op/ascribe_user_type.rs diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index de03892b994ef..4d6d3bd56f2d8 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -72,8 +72,9 @@ use std::hash::Hash; use syntax_pos::symbol::InternedString; use traits; use traits::query::{ - CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, + CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, + CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, CanonicalPredicateGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, }; use ty::{TyCtxt, FnSig, Instance, InstanceDef, ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty}; @@ -654,6 +655,7 @@ define_dep_nodes!( <'tcx> [] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>), [] DropckOutlives(CanonicalTyGoal<'tcx>), [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), + [] TypeOpAscribeUserType(CanonicalTypeOpAscribeUserTypeGoal<'tcx>), [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 62b5327ae4692..571beaae4596b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2438,6 +2438,14 @@ EnumTypeFoldableImpl! { } } +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserTypeAnnotation<'a> { + type Lifted = UserTypeAnnotation<'tcx>; + (UserTypeAnnotation::Ty)(ty), + (UserTypeAnnotation::TypeOf)(def, substs), + } +} + newtype_index! { pub struct Promoted { DEBUG_FORMAT = "promoted[{}]" diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 35f17aebc0443..13683d8544496 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -34,6 +34,9 @@ pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>> pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; +pub type CanonicalTypeOpAscribeUserTypeGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::ascribe_user_type::AscribeUserType<'tcx>>>; + pub type CanonicalTypeOpEqGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs new file mode 100644 index 0000000000000..607cfa0ec7a7c --- /dev/null +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -0,0 +1,74 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; +use mir::UserTypeAnnotation; +use traits::query::Fallible; +use ty::{self, ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AscribeUserType<'tcx> { + pub mir_ty: Ty<'tcx>, + pub variance: ty::Variance, + pub user_ty: UserTypeAnnotation<'tcx>, +} + +impl<'tcx> AscribeUserType<'tcx> { + pub fn new( + mir_ty: Ty<'tcx>, + variance: ty::Variance, + user_ty: UserTypeAnnotation<'tcx>, + ) -> Self { + AscribeUserType { mir_ty, variance, user_ty } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> { + type QueryResponse = (); + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + None + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_ascribe_user_type(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResponse<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResponse<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> { + mir_ty, variance, user_ty + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> { + type Lifted = AscribeUserType<'tcx>; + mir_ty, variance, user_ty + } +} + +impl_stable_hash_for! { + struct AscribeUserType<'tcx> { + mir_ty, variance, user_ty + } +} diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs index b292df758eeb5..d20d43cf7578c 100644 --- a/src/librustc/traits/query/type_op/mod.rs +++ b/src/librustc/traits/query/type_op/mod.rs @@ -20,6 +20,7 @@ use traits::ObligationCause; use ty::fold::TypeFoldable; use ty::{Lift, ParamEnvAnd, TyCtxt}; +pub mod ascribe_user_type; pub mod custom; pub mod eq; pub mod implied_outlives_bounds; diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index bb9346f2f468d..cad90031e970b 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -328,7 +328,7 @@ impl Visibility { } } -#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)] +#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash)] pub enum Variance { Covariant, // T <: T iff A <: B -- e.g., function return type Invariant, // T <: T iff B == A -- e.g., type of mutable cell diff --git a/src/librustc/ty/query/config.rs b/src/librustc/ty/query/config.rs index d0c3109da52f1..0f6ff93c52336 100644 --- a/src/librustc/ty/query/config.rs +++ b/src/librustc/ty/query/config.rs @@ -14,8 +14,9 @@ use hir::def_id::{CrateNum, DefId, DefIndex}; use mir::interpret::GlobalId; use traits; use traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, - CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, }; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; @@ -115,6 +116,15 @@ impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::type_op_ascribe_user_type<'tcx> { + fn describe( + _tcx: TyCtxt<'_, '_, '_>, + goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>, + ) -> Cow<'static, str> { + format!("evaluating `type_op_ascribe_user_type` `{:?}`", goal).into() + } +} + impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { fn describe(_tcx: TyCtxt<'_, '_, '_>, goal: CanonicalTypeOpEqGoal<'tcx>) -> Cow<'static, str> { format!("evaluating `type_op_eq` `{:?}`", goal).into() diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs index e4fc45f379841..a59a15da08d99 100644 --- a/src/librustc/ty/query/mod.rs +++ b/src/librustc/ty/query/mod.rs @@ -34,9 +34,12 @@ use mir::interpret::GlobalId; use session::{CompileResult, CrateDisambiguator}; use session::config::OutputFilenames; use traits::{self, Vtable}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution}; +use traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, + CanonicalTypeOpSubtypeGoal, CanonicalTypeOpProvePredicateGoal, + CanonicalTypeOpNormalizeGoal, NoSolution, +}; use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; use traits::query::normalize::NormalizationResult; use traits::query::outlives_bounds::OutlivesBound; @@ -589,6 +592,14 @@ define_queries! { <'tcx> CanonicalPredicateGoal<'tcx> ) -> Result, + /// Do not call this query directly: part of the `Eq` type-op + [] fn type_op_ascribe_user_type: TypeOpAscribeUserType( + CanonicalTypeOpAscribeUserTypeGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + /// Do not call this query directly: part of the `Eq` type-op [] fn type_op_eq: TypeOpEq( CanonicalTypeOpEqGoal<'tcx> diff --git a/src/librustc/ty/query/plumbing.rs b/src/librustc/ty/query/plumbing.rs index 71e435fea77d4..789658dcf72dc 100644 --- a/src/librustc/ty/query/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -1079,6 +1079,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ImpliedOutlivesBounds | DepKind::DropckOutlives | DepKind::EvaluateObligation | + DepKind::TypeOpAscribeUserType | DepKind::TypeOpEq | DepKind::TypeOpSubtype | DepKind::TypeOpProvePredicate | diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 6db107344747e..ace012777c7a7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -1008,6 +1008,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let ty = self.tcx().type_of(def_id); let ty = ty.subst(tcx, substs); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); let ty = self.normalize(ty, locations); self.relate_types(ty, v1, a, locations, category)?; diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index a857cdbda45ae..bf4e5bda4ebae 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -10,6 +10,7 @@ use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::infer::InferCtxt; +use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; use rustc::traits::query::type_op::prove_predicate::ProvePredicate; @@ -24,6 +25,7 @@ use std::fmt; crate fn provide(p: &mut Providers) { *p = Providers { + type_op_ascribe_user_type, type_op_eq, type_op_prove_predicate, type_op_subtype, @@ -35,6 +37,18 @@ crate fn provide(p: &mut Providers) { }; } +fn type_op_ascribe_user_type<'tcx>( + tcx: TyCtxt<'_, 'tcx, 'tcx>, + canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>, +) -> Result>>, NoSolution> { + tcx.infer_ctxt() + .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { + let (param_env, AscribeUserType { mir_ty, variance, user_ty }) = key.into_parts(); + drop((infcx, fulfill_cx, param_env, mir_ty, variance, user_ty)); + Ok(()) + }) +} + fn type_op_eq<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, From 62f0fc51126795848fff540e9776ee331753344d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 24 Oct 2018 12:08:34 -0400 Subject: [PATCH 2/2] port the relate-types code from NLL type-check into a type-op Add regression tests for #55219 and #55241 Also another test where a duplicate-like error appears to have been suppressed; I'm not 100% sure why this output changes, though I could imagine that some duplicate suppression is enabled by this PR. --- src/librustc/infer/at.rs | 22 +++ .../traits/query/type_op/ascribe_user_type.rs | 17 +- .../borrow_check/nll/type_check/mod.rs | 114 ++----------- src/librustc_traits/type_op.rs | 152 +++++++++++++++++- .../ui/nll/user-annotations/issue-55219.rs | 20 +++ .../ui/nll/user-annotations/issue-55241.rs | 28 ++++ ...ns-free-region-ordering-caller1.nll.stderr | 19 +-- 7 files changed, 244 insertions(+), 128 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/issue-55219.rs create mode 100644 src/test/ui/nll/user-annotations/issue-55241.rs diff --git a/src/librustc/infer/at.rs b/src/librustc/infer/at.rs index 89dbc76c8a65c..0e4c94aaaf394 100644 --- a/src/librustc/infer/at.rs +++ b/src/librustc/infer/at.rs @@ -142,6 +142,28 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> { self.trace(expected, actual).eq(&expected, &actual) } + pub fn relate( + self, + expected: T, + variance: ty::Variance, + actual: T, + ) -> InferResult<'tcx, ()> + where T: ToTrace<'tcx> + { + match variance { + ty::Variance::Covariant => self.sub(expected, actual), + ty::Variance::Invariant => self.eq(expected, actual), + ty::Variance::Contravariant => self.sup(expected, actual), + + // We could make this make sense but it's not readily + // exposed and I don't feel like dealing with it. Note + // that bivariance in general does a bit more than just + // *nothing*, it checks that the types are the same + // "modulo variance" basically. + ty::Variance::Bivariant => panic!("Bivariant given to `relate()`"), + } + } + /// Compute the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of diff --git a/src/librustc/traits/query/type_op/ascribe_user_type.rs b/src/librustc/traits/query/type_op/ascribe_user_type.rs index 607cfa0ec7a7c..b3955b8f864e5 100644 --- a/src/librustc/traits/query/type_op/ascribe_user_type.rs +++ b/src/librustc/traits/query/type_op/ascribe_user_type.rs @@ -9,24 +9,27 @@ // except according to those terms. use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResponse, QueryResponse}; -use mir::UserTypeAnnotation; use traits::query::Fallible; +use hir::def_id::DefId; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; +use ty::subst::UserSubsts; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct AscribeUserType<'tcx> { pub mir_ty: Ty<'tcx>, pub variance: ty::Variance, - pub user_ty: UserTypeAnnotation<'tcx>, + pub def_id: DefId, + pub user_substs: UserSubsts<'tcx>, } impl<'tcx> AscribeUserType<'tcx> { pub fn new( mir_ty: Ty<'tcx>, variance: ty::Variance, - user_ty: UserTypeAnnotation<'tcx>, + def_id: DefId, + user_substs: UserSubsts<'tcx>, ) -> Self { - AscribeUserType { mir_ty, variance, user_ty } + AscribeUserType { mir_ty, variance, def_id, user_substs } } } @@ -56,19 +59,19 @@ impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for AscribeUserType<'tcx> BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for AscribeUserType<'tcx> { - mir_ty, variance, user_ty + mir_ty, variance, def_id, user_substs } } BraceStructLiftImpl! { impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> { type Lifted = AscribeUserType<'tcx>; - mir_ty, variance, user_ty + mir_ty, variance, def_id, user_substs } } impl_stable_hash_for! { struct AscribeUserType<'tcx> { - mir_ty, variance, user_ty + mir_ty, variance, def_id, user_substs } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index ace012777c7a7..bbbe02fda6a84 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -42,7 +42,7 @@ use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; -use rustc::ty::subst::{Subst, Substs, UnpackedKind, UserSelfTy, UserSubsts}; +use rustc::ty::subst::{Subst, Substs, UnpackedKind}; use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; @@ -975,127 +975,43 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { - let tcx = self.tcx(); - debug!( - "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", - a, v, user_ty, locations + "relate_type_and_user_type(a={:?}, v={:?}, user_ty={:?}, locations={:?})", + a, v, user_ty, locations, ); - // The `TypeRelating` code assumes that "unresolved inference - // variables" appear in the "a" side, so flip `Contravariant` - // ambient variance to get the right relationship. - let v1 = ty::Contravariant.xform(v); - match user_ty { UserTypeAnnotation::Ty(canonical_ty) => { let (ty, _) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); - self.relate_types(ty, v1, a, locations, category)?; + // The `TypeRelating` code assumes that "unresolved inference + // variables" appear in the "a" side, so flip `Contravariant` + // ambient variance to get the right relationship. + let v1 = ty::Contravariant.xform(v); - self.prove_predicate(ty::Predicate::WellFormed(ty), locations, category); + self.relate_types(ty, v1, a, locations, category)?; } UserTypeAnnotation::TypeOf(def_id, canonical_substs) => { let ( - UserSubsts { - substs, - user_self_ty, - }, + user_substs, _, ) = self.infcx .instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - let ty = self.tcx().type_of(def_id); - let ty = ty.subst(tcx, substs); - debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); - let ty = self.normalize(ty, locations); - - self.relate_types(ty, v1, a, locations, category)?; - - if let Some(UserSelfTy { - impl_def_id, - self_ty, - }) = user_self_ty - { - let impl_self_ty = tcx.type_of(impl_def_id); - let impl_self_ty = impl_self_ty.subst(tcx, &substs); - let impl_self_ty = self.normalize(impl_self_ty, locations); - - // There may be type variables in `substs` and hence - // in `impl_self_ty`, but they should all have been - // resolved to some fixed value during the first call - // to `relate`, above. Therefore, if we use - // `resolve_type_vars_if_possible` we should get to - // something without type variables. This is important - // because the `b` type in `relate_with_variance` - // below is not permitted to have inference variables. - let impl_self_ty = self.infcx.resolve_type_vars_if_possible(&impl_self_ty); - assert!(!impl_self_ty.has_infer_types()); - - self.eq_types(self_ty, impl_self_ty, locations, category)?; - - self.prove_predicate( - ty::Predicate::WellFormed(impl_self_ty), - locations, - category, - ); - } - - // Prove the predicates coming along with `def_id`. - // - // Also, normalize the `instantiated_predicates` - // because otherwise we wind up with duplicate "type - // outlives" error messages. - let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs); - let instantiated_predicates = self.fold_to_region_vid(instantiated_predicates); - self.normalize_and_prove_instantiated_predicates( - instantiated_predicates, + self.fully_perform_op( locations, - ); - - // In addition to proving the predicates, we have to - // prove that `ty` is well-formed -- this is because - // the WF of `ty` is predicated on the substs being - // well-formed, and we haven't proven *that*. We don't - // want to prove the WF of types from `substs` directly because they - // haven't been normalized. - // - // FIXME(nmatsakis): Well, perhaps we should normalize - // 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::Predicate::WellFormed(ty), locations, category); + category, + self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new( + a, v, def_id, user_substs, + )), + )?; } } Ok(()) } - /// Replace all free regions in `value` with their NLL `RegionVid` - /// equivalents; if not in NLL, does nothing. This is never - /// particularly necessary -- we'll do it lazilly as we process - /// the value anyway -- but in some specific cases it is useful to - /// normalize so we can suppress duplicate error messages. - fn fold_to_region_vid(&self, value: T) -> T - where - T: TypeFoldable<'tcx>, - { - if let Some(borrowck_context) = &self.borrowck_context { - self.tcx().fold_regions(&value, &mut false, |r, _debruijn| { - if r.has_free_regions() { - self.tcx().mk_region(ty::RegionKind::ReVar( - borrowck_context.universal_regions.to_region_vid(r), - )) - } else { - r - } - }) - } else { - value - } - } - fn eq_opaque_type_and_type( &mut self, revealed_ty: Ty<'tcx>, diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs index bf4e5bda4ebae..cf274a9c85105 100644 --- a/src/librustc_traits/type_op.rs +++ b/src/librustc_traits/type_op.rs @@ -8,20 +8,28 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use rustc::infer::at::ToTrace; use rustc::infer::canonical::{Canonical, QueryResponse}; use rustc::infer::InferCtxt; +use rustc::hir::def_id::DefId; use rustc::traits::query::type_op::ascribe_user_type::AscribeUserType; use rustc::traits::query::type_op::eq::Eq; use rustc::traits::query::type_op::normalize::Normalize; use rustc::traits::query::type_op::prove_predicate::ProvePredicate; use rustc::traits::query::type_op::subtype::Subtype; use rustc::traits::query::{Fallible, NoSolution}; -use rustc::traits::{FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, - TraitEngineExt}; +use rustc::traits::{ + FulfillmentContext, Normalized, Obligation, ObligationCause, TraitEngine, TraitEngineExt, +}; use rustc::ty::query::Providers; -use rustc::ty::{FnSig, Lift, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable}; +use rustc::ty::subst::{Kind, Subst, UserSelfTy, UserSubsts}; +use rustc::ty::{ + FnSig, Lift, ParamEnv, ParamEnvAnd, PolyFnSig, Predicate, Ty, TyCtxt, TypeFoldable, Variance, +}; use rustc_data_structures::sync::Lrc; use std::fmt; +use syntax::ast; +use syntax_pos::DUMMY_SP; crate fn provide(p: &mut Providers) { *p = Providers { @@ -43,12 +51,146 @@ fn type_op_ascribe_user_type<'tcx>( ) -> Result>>, NoSolution> { tcx.infer_ctxt() .enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| { - let (param_env, AscribeUserType { mir_ty, variance, user_ty }) = key.into_parts(); - drop((infcx, fulfill_cx, param_env, mir_ty, variance, user_ty)); + let ( + param_env, + AscribeUserType { + mir_ty, + variance, + def_id, + user_substs, + }, + ) = key.into_parts(); + + debug!( + "type_op_ascribe_user_type(\ + mir_ty={:?}, variance={:?}, def_id={:?}, user_substs={:?}\ + )", + mir_ty, variance, def_id, user_substs, + ); + + let mut cx = AscribeUserTypeCx { + infcx, + param_env, + fulfill_cx, + }; + cx.relate_mir_and_user_ty(mir_ty, variance, def_id, user_substs)?; + Ok(()) }) } +struct AscribeUserTypeCx<'me, 'gcx: 'tcx, 'tcx: 'me> { + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + param_env: ParamEnv<'tcx>, + fulfill_cx: &'me mut FulfillmentContext<'tcx>, +} + +impl AscribeUserTypeCx<'me, 'gcx, 'tcx> { + fn normalize(&mut self, value: T) -> T + where + T: TypeFoldable<'tcx>, + { + self.infcx + .partially_normalize_associated_types_in( + DUMMY_SP, + ast::CRATE_NODE_ID, + self.param_env, + &value, + ) + .into_value_registering_obligations(self.infcx, self.fulfill_cx) + } + + fn relate(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution> + where + T: ToTrace<'tcx>, + { + Ok(self.infcx + .at(&ObligationCause::dummy(), self.param_env) + .relate(a, variance, b)? + .into_value_registering_obligations(self.infcx, self.fulfill_cx)) + } + + fn prove_predicate(&mut self, predicate: Predicate<'tcx>) { + self.fulfill_cx.register_predicate_obligation( + self.infcx, + Obligation::new(ObligationCause::dummy(), self.param_env, predicate), + ); + } + + fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn subst(&self, value: T, substs: &[Kind<'tcx>]) -> T + where + T: TypeFoldable<'tcx>, + { + value.subst(self.tcx(), substs) + } + + fn relate_mir_and_user_ty( + &mut self, + mir_ty: Ty<'tcx>, + variance: Variance, + def_id: DefId, + user_substs: UserSubsts<'tcx>, + ) -> Result<(), NoSolution> { + let UserSubsts { + substs, + user_self_ty, + } = user_substs; + + let ty = self.tcx().type_of(def_id); + let ty = self.subst(ty, substs); + debug!("relate_type_and_user_type: ty of def-id is {:?}", ty); + let ty = self.normalize(ty); + + self.relate(mir_ty, variance, ty)?; + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty + { + let impl_self_ty = self.tcx().type_of(impl_def_id); + let impl_self_ty = self.subst(impl_self_ty, &substs); + let impl_self_ty = self.normalize(impl_self_ty); + + self.relate(self_ty, Variance::Invariant, impl_self_ty)?; + + self.prove_predicate(Predicate::WellFormed(impl_self_ty)); + } + + // Prove the predicates coming along with `def_id`. + // + // Also, normalize the `instantiated_predicates` + // because otherwise we wind up with duplicate "type + // outlives" error messages. + let instantiated_predicates = self.tcx() + .predicates_of(def_id) + .instantiate(self.tcx(), substs); + for instantiated_predicate in instantiated_predicates.predicates { + let instantiated_predicate = self.normalize(instantiated_predicate); + self.prove_predicate(instantiated_predicate); + } + + // In addition to proving the predicates, we have to + // prove that `ty` is well-formed -- this is because + // the WF of `ty` is predicated on the substs being + // well-formed, and we haven't proven *that*. We don't + // want to prove the WF of types from `substs` directly because they + // haven't been normalized. + // + // FIXME(nmatsakis): Well, perhaps we should normalize + // 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(Predicate::WellFormed(ty)); + + Ok(()) + } +} + fn type_op_eq<'tcx>( tcx: TyCtxt<'_, 'tcx, 'tcx>, canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>, diff --git a/src/test/ui/nll/user-annotations/issue-55219.rs b/src/test/ui/nll/user-annotations/issue-55219.rs new file mode 100644 index 0000000000000..7daa5a59b9977 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55219.rs @@ -0,0 +1,20 @@ +// Regression test for #55219: +// +// The `Self::HASH_LEN` here expands to a "self-type" where `T` is not +// known. This unbound inference variable was causing an ICE. +// +// run-pass + +#![feature(nll)] + +pub struct Foo(T); + +impl Foo { + const HASH_LEN: usize = 20; + + fn stuff() { + let _ = Self::HASH_LEN; + } +} + +fn main() { } diff --git a/src/test/ui/nll/user-annotations/issue-55241.rs b/src/test/ui/nll/user-annotations/issue-55241.rs new file mode 100644 index 0000000000000..e5600803df856 --- /dev/null +++ b/src/test/ui/nll/user-annotations/issue-55241.rs @@ -0,0 +1,28 @@ +// Regression test for #55241: +// +// The reference to `C::HASHED_NULL_NODE` resulted in a type like `>::Out`; normalizing this type requires knowing the +// value of `_`; solving that requires having normalized, so we can +// test against `C: NodeCodec` in the environment. +// +// run-pass + +#![feature(nll)] + +pub trait Hasher { + type Out: Eq; +} + +pub trait NodeCodec { + const HASHED_NULL_NODE: H::Out; +} + +pub trait Trie> { + /// Return the root of the trie. + fn root(&self) -> &H::Out; + + /// Is the trie empty? + fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE } +} + +fn main() { } diff --git a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr index c6bd5b7fa0d24..39f193c55f77a 100644 --- a/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr +++ b/src/test/ui/regions/regions-free-region-ordering-caller1.nll.stderr @@ -12,21 +12,6 @@ LL | let z: &'a & usize = &(&y); LL | } | - temporary value is freed at the end of this statement -error[E0597]: `y` does not live long enough - --> $DIR/regions-free-region-ordering-caller1.rs:19:27 - | -LL | fn call1<'a>(x: &'a usize) { - | -- lifetime `'a` defined here -... -LL | let z: &'a & usize = &(&y); - | ----------- ^^^^ borrowed value does not live long enough - | | - | type annotation requires that `y` is borrowed for `'a` -... -LL | } - | - `y` dropped here while still borrowed - -error: aborting due to 2 previous errors +error: aborting due to previous error -Some errors occurred: E0597, E0716. -For more information about an error, try `rustc --explain E0597`. +For more information about this error, try `rustc --explain E0716`.