Auto merge of #55323 - nikomatsakis:nll-ICE-55219-and-55241, r=pnkfelix
introduce type-op for user-type ascription in NLL Handle user-type ascription in a type operator, which gives us a lot more flexibility around the order in which we resolve things. r? @pnkfelix Fixes #55219 Fixes #55241
This commit is contained in:
commit
3476ac0bee
15 changed files with 367 additions and 126 deletions
|
|
@ -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>),
|
||||
|
|
|
|||
|
|
@ -142,6 +142,28 @@ impl<'a, 'gcx, 'tcx> At<'a, 'gcx, 'tcx> {
|
|||
self.trace(expected, actual).eq(&expected, &actual)
|
||||
}
|
||||
|
||||
pub fn relate<T>(
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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[{}]"
|
||||
|
|
|
|||
|
|
@ -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>>>;
|
||||
|
||||
|
|
|
|||
77
src/librustc/traits/query/type_op/ascribe_user_type.rs
Normal file
77
src/librustc/traits/query/type_op/ascribe_user_type.rs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 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 def_id: DefId,
|
||||
pub user_substs: UserSubsts<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> AscribeUserType<'tcx> {
|
||||
pub fn new(
|
||||
mir_ty: Ty<'tcx>,
|
||||
variance: ty::Variance,
|
||||
def_id: DefId,
|
||||
user_substs: UserSubsts<'tcx>,
|
||||
) -> Self {
|
||||
AscribeUserType { mir_ty, variance, def_id, user_substs }
|
||||
}
|
||||
}
|
||||
|
||||
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<Self::QueryResponse> {
|
||||
None
|
||||
}
|
||||
|
||||
fn perform_query(
|
||||
tcx: TyCtxt<'_, 'gcx, 'tcx>,
|
||||
canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>,
|
||||
) -> Fallible<CanonicalizedQueryResponse<'gcx, ()>> {
|
||||
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, def_id, user_substs
|
||||
}
|
||||
}
|
||||
|
||||
BraceStructLiftImpl! {
|
||||
impl<'a, 'tcx> Lift<'tcx> for AscribeUserType<'a> {
|
||||
type Lifted = AscribeUserType<'tcx>;
|
||||
mir_ty, variance, def_id, user_substs
|
||||
}
|
||||
}
|
||||
|
||||
impl_stable_hash_for! {
|
||||
struct AscribeUserType<'tcx> {
|
||||
mir_ty, variance, def_id, user_substs
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ impl Visibility {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcDecodable, RustcEncodable, Copy)]
|
||||
#[derive(Copy, Clone, PartialEq, Eq, RustcDecodable, RustcEncodable, Hash)]
|
||||
pub enum Variance {
|
||||
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
|
||||
Invariant, // T<A> <: T<B> iff B == A -- e.g., type of mutable cell
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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<traits::EvaluationResult, traits::OverflowError>,
|
||||
|
||||
/// Do not call this query directly: part of the `Eq` type-op
|
||||
[] fn type_op_ascribe_user_type: TypeOpAscribeUserType(
|
||||
CanonicalTypeOpAscribeUserTypeGoal<'tcx>
|
||||
) -> Result<
|
||||
Lrc<Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>>,
|
||||
NoSolution,
|
||||
>,
|
||||
|
||||
/// Do not call this query directly: part of the `Eq` type-op
|
||||
[] fn type_op_eq: TypeOpEq(
|
||||
CanonicalTypeOpEqGoal<'tcx>
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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,126 +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);
|
||||
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<T>(&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>,
|
||||
|
|
|
|||
|
|
@ -8,22 +8,32 @@
|
|||
// 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 {
|
||||
type_op_ascribe_user_type,
|
||||
type_op_eq,
|
||||
type_op_prove_predicate,
|
||||
type_op_subtype,
|
||||
|
|
@ -35,6 +45,152 @@ 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<Lrc<Canonical<'tcx, QueryResponse<'tcx, ()>>>, NoSolution> {
|
||||
tcx.infer_ctxt()
|
||||
.enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
|
||||
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<T>(&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<T>(&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<T>(&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>>>,
|
||||
|
|
|
|||
20
src/test/ui/nll/user-annotations/issue-55219.rs
Normal file
20
src/test/ui/nll/user-annotations/issue-55219.rs
Normal file
|
|
@ -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>(T);
|
||||
|
||||
impl<T> Foo<T> {
|
||||
const HASH_LEN: usize = 20;
|
||||
|
||||
fn stuff() {
|
||||
let _ = Self::HASH_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
28
src/test/ui/nll/user-annotations/issue-55241.rs
Normal file
28
src/test/ui/nll/user-annotations/issue-55241.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
// Regression test for #55241:
|
||||
//
|
||||
// The reference to `C::HASHED_NULL_NODE` resulted in a type like `<C
|
||||
// as NodeCodec<_>>::Out`; normalizing this type requires knowing the
|
||||
// value of `_`; solving that requires having normalized, so we can
|
||||
// test against `C: NodeCodec<H>` in the environment.
|
||||
//
|
||||
// run-pass
|
||||
|
||||
#![feature(nll)]
|
||||
|
||||
pub trait Hasher {
|
||||
type Out: Eq;
|
||||
}
|
||||
|
||||
pub trait NodeCodec<H: Hasher> {
|
||||
const HASHED_NULL_NODE: H::Out;
|
||||
}
|
||||
|
||||
pub trait Trie<H: Hasher, C: NodeCodec<H>> {
|
||||
/// 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() { }
|
||||
|
|
@ -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 previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
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`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue