From 4b69edc19e5a752011d867a2ac6c8d8a58548c07 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 9 Oct 2018 16:43:57 -0400 Subject: [PATCH 01/19] rename to `user_substs_applied_to_def` for consistency --- src/librustc_mir/hair/cx/expr.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index c969a3ef348..813400422db 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -759,7 +759,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } -fn user_annotated_ty_for_def( +fn user_substs_applied_to_def( cx: &mut Cx<'a, 'gcx, 'tcx>, hir_id: hir::HirId, def: &Def, @@ -795,7 +795,7 @@ fn user_annotated_ty_for_def( cx.user_substs_applied_to_ty_of_hir_id(hir_id), _ => - bug!("user_annotated_ty_for_def: unexpected def {:?} at {:?}", def, hir_id) + bug!("user_substs_applied_to_def: unexpected def {:?} at {:?}", def, hir_id) } } @@ -815,7 +815,7 @@ fn method_callee<'a, 'gcx, 'tcx>( .unwrap_or_else(|| { span_bug!(expr.span, "no type-dependent def for method callee") }); - let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, def); + let user_ty = user_substs_applied_to_def(cx, expr.hir_id, def); (def.def_id(), cx.tables().node_substs(expr.hir_id), user_ty) } }; @@ -882,7 +882,7 @@ fn convert_path_expr<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) | Def::SelfCtor(..) => { - let user_ty = user_annotated_ty_for_def(cx, expr.hir_id, &def); + let user_ty = user_substs_applied_to_def(cx, expr.hir_id, &def); ExprKind::Literal { literal: ty::Const::zero_sized( cx.tcx, From 24bee005b646692b265af026cf863acf9a322460 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 14:42:56 -0400 Subject: [PATCH 02/19] add `force_instantiate_unchecked` method --- src/librustc/infer/mod.rs | 59 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index ef9886e06d4..cbfdf58adee 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1230,6 +1230,65 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.inlined_shallow_resolve(typ) } + /// A hacky sort of method used by the NLL type-relating code: + /// + /// - `var` must be some unbound type variable. + /// - `value` must be a suitable type to use as its value. + /// + /// `var` will then be equated with `value`. Note that this + /// sidesteps a number of important checks, such as the "occurs + /// check" that prevents cyclic types, so it is important not to + /// use this method during regular type-check. + pub fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { + match (&var.sty, &value.sty) { + (&ty::Infer(ty::TyVar(vid)), _) => { + let mut type_variables = self.type_variables.borrow_mut(); + + // In NLL, we don't have type inference variables + // floating around, so we can do this rather imprecise + // variant of the occurs-check. + assert!(!value.has_infer_types()); + + type_variables.instantiate(vid, value); + } + + (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + int_unification_table + .unify_var_value(vid, Some(ty::IntVarValue::IntType(value))) + .unwrap_or_else(|_| { + bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); + }); + } + + (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + int_unification_table + .unify_var_value(vid, Some(ty::IntVarValue::UintType(value))) + .unwrap_or_else(|_| { + bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); + }); + } + + (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => { + let mut float_unification_table = self.float_unification_table.borrow_mut(); + float_unification_table + .unify_var_value(vid, Some(ty::FloatVarValue(value))) + .unwrap_or_else(|_| { + bug!("failed to unify float var `{:?}` with `{:?}`", vid, value) + }); + } + + _ => { + bug!( + "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}", + var, + value, + ); + } + } + } + pub fn resolve_type_vars_if_possible(&self, value: &T) -> T where T: TypeFoldable<'tcx>, From ca52427d06eaf7151f4381b9f4decff4490f6068 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 14:56:24 -0400 Subject: [PATCH 03/19] make `TypeRelating` take an infcx again At some point, I had thought to use this code to handle equality comparisons for the `IfEq` verify bounds; at that point, we might not have had an infcx to talk about. But we wound up doing "SCC representatives" instead, so that's fine. --- .../borrow_check/nll/type_check/relate_tys.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 96cc1c0afec..d4e047673d8 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -32,7 +32,7 @@ pub(super) fn sub_types<'tcx>( ) -> Fallible<()> { debug!("sub_types(a={:?}, b={:?}, locations={:?})", a, b, locations); TypeRelating::new( - infcx.tcx, + infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), ty::Variance::Covariant, ty::List::empty(), @@ -51,7 +51,7 @@ pub(super) fn eq_types<'tcx>( ) -> Fallible<()> { debug!("eq_types(a={:?}, b={:?}, locations={:?})", a, b, locations); TypeRelating::new( - infcx.tcx, + infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), ty::Variance::Invariant, ty::List::empty(), @@ -86,7 +86,7 @@ pub(super) fn relate_type_and_user_type<'tcx>( let v1 = ty::Contravariant.xform(v); let mut type_relating = TypeRelating::new( - infcx.tcx, + infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), v1, b_variables, @@ -109,7 +109,7 @@ struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D> where D: TypeRelatingDelegate<'tcx>, { - tcx: TyCtxt<'me, 'gcx, 'tcx>, + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, /// Callback to use when we deduce an outlives relationship delegate: D, @@ -276,14 +276,14 @@ where D: TypeRelatingDelegate<'tcx>, { fn new( - tcx: TyCtxt<'me, 'gcx, 'tcx>, + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, delegate: D, ambient_variance: ty::Variance, canonical_var_infos: CanonicalVarInfos<'tcx>, ) -> Self { let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len()); Self { - tcx, + infcx, delegate, ambient_variance, canonical_var_values, @@ -432,7 +432,7 @@ where fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { TypeGeneralizer { - tcx: self.tcx, + tcx: self.infcx.tcx, delegate: &mut self.delegate, first_free_index: ty::INNERMOST, ambient_variance: self.ambient_variance, @@ -450,7 +450,7 @@ where D: TypeRelatingDelegate<'tcx>, { fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { - self.tcx + self.infcx.tcx } fn tag(&self) -> &'static str { From a3409a1640785c6280693a21ec39603615353d28 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 16:21:41 -0400 Subject: [PATCH 04/19] make `instantiate_canonical_with_fresh_inference_vars` public again This used to be public, then I made it private in a previous PR, but there really wasn't a strong need for that. --- src/librustc/infer/canonical/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs index a78b5b7d072..1863f08930f 100644 --- a/src/librustc/infer/canonical/mod.rs +++ b/src/librustc/infer/canonical/mod.rs @@ -241,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// canonicalized) then represents the values that you computed /// for each of the canonical inputs to your query. - pub(in infer) fn instantiate_canonical_with_fresh_inference_vars( + pub fn instantiate_canonical_with_fresh_inference_vars( &self, span: Span, canonical: &Canonical<'tcx, T>, @@ -249,9 +249,6 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { where T: TypeFoldable<'tcx>, { - assert_eq!(self.universe(), ty::UniverseIndex::ROOT, "infcx not newly created"); - assert_eq!(self.type_variables.borrow().num_vars(), 0, "infcx not newly created"); - let canonical_inference_vars = self.fresh_inference_vars_for_canonical_vars(span, canonical.variables); let result = canonical.substitute(self.tcx, &canonical_inference_vars); From b6a080e9d7d5d50642b2dee07c81ec30fcef3e74 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 15:10:05 -0400 Subject: [PATCH 05/19] rework `relate_type_and_user_type` to use type inference variables We used to use a kind of "home-grown" variant where we tracked the value of each canonical variable. --- .../borrow_check/nll/type_check/relate_tys.rs | 109 ++++++------------ 1 file changed, 37 insertions(+), 72 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index d4e047673d8..26cd939a4da 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -10,16 +10,15 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; -use rustc::infer::canonical::{Canonical, CanonicalVarInfos, CanonicalVarValues}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::ConstraintCategory; use rustc::traits::query::Fallible; use rustc::ty::fold::{TypeFoldable, TypeVisitor}; use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc::ty::subst::Kind; -use rustc::ty::{self, CanonicalTy, CanonicalVar, Ty, TyCtxt}; +use rustc::ty::{self, CanonicalTy, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::indexed_vec::IndexVec; +use syntax::source_map::DUMMY_SP; /// Adds sufficient constraints to ensure that `a <: b`. pub(super) fn sub_types<'tcx>( @@ -35,7 +34,6 @@ pub(super) fn sub_types<'tcx>( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), ty::Variance::Covariant, - ty::List::empty(), ).relate(&a, &b)?; Ok(()) } @@ -54,7 +52,6 @@ pub(super) fn eq_types<'tcx>( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), ty::Variance::Invariant, - ty::List::empty(), ).relate(&a, &b)?; Ok(()) } @@ -66,19 +63,20 @@ pub(super) fn relate_type_and_user_type<'tcx>( infcx: &InferCtxt<'_, '_, 'tcx>, a: Ty<'tcx>, v: ty::Variance, - b: CanonicalTy<'tcx>, + canonical_b: CanonicalTy<'tcx>, locations: Locations, category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible> { debug!( - "sub_type_and_user_type(a={:?}, b={:?}, locations={:?})", - a, b, locations + "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", + a, v, canonical_b, locations + ); + + let (b, _values) = infcx.instantiate_canonical_with_fresh_inference_vars( + DUMMY_SP, + &canonical_b, ); - let Canonical { - variables: b_variables, - value: b_value, - } = b; // The `TypeRelating` code assumes that the "canonical variables" // appear in the "a" side, so flip `Contravariant` ambient @@ -89,20 +87,10 @@ pub(super) fn relate_type_and_user_type<'tcx>( infcx, NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), v1, - b_variables, ); - type_relating.relate(&b_value, &a)?; + type_relating.relate(&b, &a)?; - Ok(b.substitute( - infcx.tcx, - &CanonicalVarValues { - var_values: type_relating - .canonical_var_values - .into_iter() - .map(|x| x.expect("unsubstituted canonical variable")) - .collect(), - }, - )) + Ok(b) } struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D> @@ -136,19 +124,6 @@ where /// Same as `a_scopes`, but for the `b` type. b_scopes: Vec>, - - /// As we execute, the type on the LHS *may* come from a canonical - /// source. In that case, we will sometimes find a constraint like - /// `?0 = B`, where `B` is a type from the RHS. The first time we - /// find that, we simply record `B` (and the list of scopes that - /// tells us how to *interpret* `B`). The next time we encounter - /// `?0`, then, we can read this value out and use it. - /// - /// One problem: these variables may be in some other universe, - /// how can we enforce that? I guess I could add some kind of - /// "minimum universe constraint" that we can feed to the NLL checker. - /// --> also, we know this doesn't happen - canonical_var_values: IndexVec>>, } trait TypeRelatingDelegate<'tcx> { @@ -279,14 +254,11 @@ where infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, delegate: D, ambient_variance: ty::Variance, - canonical_var_infos: CanonicalVarInfos<'tcx>, ) -> Self { - let canonical_var_values = IndexVec::from_elem_n(None, canonical_var_infos.len()); Self { infcx, delegate, ambient_variance, - canonical_var_values, a_scopes: vec![], b_scopes: vec![], } @@ -400,19 +372,13 @@ where /// equated, then equate it again. fn relate_var( &mut self, - var: CanonicalVar, - b_kind: Kind<'tcx>, - ) -> RelateResult<'tcx, Kind<'tcx>> { - debug!("equate_var(var={:?}, b_kind={:?})", var, b_kind); + var_ty: Ty<'tcx>, + value_ty: Ty<'tcx>, + ) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty); - let generalized_kind = match self.canonical_var_values[var] { - Some(v) => v, - None => { - let generalized_kind = self.generalize_value(b_kind); - self.canonical_var_values[var] = Some(generalized_kind); - generalized_kind - } - }; + let generalized_ty = self.generalize_value(value_ty); + self.infcx.force_instantiate_unchecked(var_ty, generalized_ty); // The generalized values we extract from `canonical_var_values` have // been fully instantiated and hence the set of scopes we have @@ -421,16 +387,16 @@ where let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]); // Relate the generalized kind to the original one. - let result = self.relate(&generalized_kind, &b_kind); + let result = self.relate(&generalized_ty, &value_ty); // Restore the old scopes now. self.a_scopes = old_a_scopes; debug!("equate_var: complete, result = {:?}", result); - return result; + result } - fn generalize_value(&mut self, kind: Kind<'tcx>) -> Kind<'tcx> { + fn generalize_value>(&mut self, value: T) -> T { TypeGeneralizer { tcx: self.infcx.tcx, delegate: &mut self.delegate, @@ -440,7 +406,7 @@ where // These always correspond to an `_` or `'_` written by // user, and those are always in the root universe. universe: ty::UniverseIndex::ROOT, - }.relate(&kind, &kind) + }.relate(&value, &value) .unwrap() } } @@ -490,18 +456,22 @@ where } fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - // Watch out for the case that we are matching a `?T` against the - // right-hand side. - if let ty::Infer(ty::CanonicalTy(var)) = a.sty { - self.relate_var(var, b.into())?; - Ok(a) - } else { - debug!( - "tys(a={:?}, b={:?}, variance={:?})", - a, b, self.ambient_variance - ); + let a = self.infcx.shallow_resolve(a); + match a.sty { + ty::Infer(ty::TyVar(_)) | + ty::Infer(ty::IntVar(_)) | + ty::Infer(ty::FloatVar(_)) => { + self.relate_var(a.into(), b.into()) + } - relate::super_relate_tys(self, a, b) + _ => { + debug!( + "tys(a={:?}, b={:?}, variance={:?})", + a, b, self.ambient_variance + ); + + relate::super_relate_tys(self, a, b) + } } } @@ -510,11 +480,6 @@ where a: ty::Region<'tcx>, b: ty::Region<'tcx>, ) -> RelateResult<'tcx, ty::Region<'tcx>> { - if let ty::ReCanonical(var) = a { - self.relate_var(*var, b.into())?; - return Ok(a); - } - debug!( "regions(a={:?}, b={:?}, variance={:?})", a, b, self.ambient_variance From e7ed997d87a1769bd68a86412ae2a417e4d36b99 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 16:21:37 -0400 Subject: [PATCH 06/19] extract `type_relate` into the inference context as `nll_relate` The name is not great. Nor is the existence of this code great. It should be merged with the main "type relating code" at some point. --- src/librustc/infer/mod.rs | 3 +- src/librustc/infer/nll_relate/mod.rs | 675 ++++++++++++++++++ .../borrow_check/nll/type_check/relate_tys.rs | 654 +---------------- 3 files changed, 681 insertions(+), 651 deletions(-) create mode 100644 src/librustc/infer/nll_relate/mod.rs diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index cbfdf58adee..9d56cf5aabe 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -62,6 +62,7 @@ mod higher_ranked; pub mod lattice; mod lexical_region_resolve; mod lub; +pub mod nll_relate; pub mod opaque_types; pub mod outlives; pub mod region_constraints; @@ -1239,7 +1240,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// sidesteps a number of important checks, such as the "occurs /// check" that prevents cyclic types, so it is important not to /// use this method during regular type-check. - pub fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { + fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { match (&var.sty, &value.sty) { (&ty::Infer(ty::TyVar(vid)), _) => { let mut type_variables = self.type_variables.borrow_mut(); diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs new file mode 100644 index 00000000000..bd126b17971 --- /dev/null +++ b/src/librustc/infer/nll_relate/mod.rs @@ -0,0 +1,675 @@ +// Copyright 2017 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. + +//! This code is kind of an alternate way of doing subtyping, +//! supertyping, and type equating, distinct from the `combine.rs` +//! code but very similar in its effect and design. Eventually the two +//! ought to be merged. This code is intended for use in NLL. +//! +//! Here are the key differences: +//! +//! - This code generally assumes that there are no unbound type +//! inferences variables, because at NLL +//! time types are fully inferred up-to regions. +//! - Actually, to support user-given type annotations like +//! `Vec<_>`, we do have some measure of support for type +//! inference variables, but we impose some simplifying +//! assumptions on them that would not be suitable for the infer +//! code more generally. This could be fixed. +//! - This code uses "universes" to handle higher-ranked regions and +//! not the leak-check. This is "more correct" than what rustc does +//! and we are generally migrating in this direction, but NLL had to +//! get there first. + +use crate::infer::InferCtxt; +use crate::ty::fold::{TypeFoldable, TypeVisitor}; +use crate::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use crate::ty::subst::Kind; +use crate::ty::{self, Ty, TyCtxt}; +use rustc_data_structures::fx::FxHashMap; + +pub struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D> +where + D: TypeRelatingDelegate<'tcx>, +{ + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + + /// Callback to use when we deduce an outlives relationship + delegate: D, + + /// How are we relating `a` and `b`? + /// + /// - covariant means `a <: b` + /// - contravariant means `b <: a` + /// - invariant means `a == b + /// - bivariant means that it doesn't matter + ambient_variance: ty::Variance, + + /// When we pass through a set of binders (e.g., when looking into + /// a `fn` type), we push a new bound region scope onto here. This + /// will contain the instantiated region for each region in those + /// binders. When we then encounter a `ReLateBound(d, br)`, we can + /// use the debruijn index `d` to find the right scope, and then + /// bound region name `br` to find the specific instantiation from + /// within that scope. See `replace_bound_region`. + /// + /// This field stores the instantiations for late-bound regions in + /// the `a` type. + a_scopes: Vec>, + + /// Same as `a_scopes`, but for the `b` type. + b_scopes: Vec>, +} + +pub trait TypeRelatingDelegate<'tcx> { + /// Push a constraint `sup: sub` -- this constraint must be + /// satisfied for the two types to be related. `sub` and `sup` may + /// be regions from the type or new variables created through the + /// delegate. + fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); + + /// Creates a new universe index. Used when instantiating placeholders. + fn create_next_universe(&mut self) -> ty::UniverseIndex; + + /// Creates a new region variable representing a higher-ranked + /// region that is instantiated existentially. This creates an + /// inference variable, typically. + /// + /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then + /// we will invoke this method to instantiate `'a` with an + /// inference variable (though `'b` would be instantiated first, + /// as a placeholder). + fn next_existential_region_var(&mut self) -> ty::Region<'tcx>; + + /// Creates a new region variable representing a + /// higher-ranked region that is instantiated universally. + /// This creates a new region placeholder, typically. + /// + /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then + /// we will invoke this method to instantiate `'b` with a + /// placeholder region. + fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>; + + /// Creates a new existential region in the given universe. This + /// is used when handling subtyping and type variables -- if we + /// have that `?X <: Foo<'a>`, for example, we would instantiate + /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh + /// existential variable created by this function. We would then + /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives + /// relation stating that `'?0: 'a`). + fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; +} + +#[derive(Clone, Debug)] +struct ScopesAndKind<'tcx> { + scopes: Vec>, + kind: Kind<'tcx>, +} + +#[derive(Clone, Debug, Default)] +struct BoundRegionScope<'tcx> { + map: FxHashMap>, +} + +#[derive(Copy, Clone)] +struct UniversallyQuantified(bool); + +impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D> +where + D: TypeRelatingDelegate<'tcx>, +{ + pub fn new( + infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, + delegate: D, + ambient_variance: ty::Variance, + ) -> Self { + Self { + infcx, + delegate, + ambient_variance, + a_scopes: vec![], + b_scopes: vec![], + } + } + + fn ambient_covariance(&self) -> bool { + match self.ambient_variance { + ty::Variance::Covariant | ty::Variance::Invariant => true, + ty::Variance::Contravariant | ty::Variance::Bivariant => false, + } + } + + fn ambient_contravariance(&self) -> bool { + match self.ambient_variance { + ty::Variance::Contravariant | ty::Variance::Invariant => true, + ty::Variance::Covariant | ty::Variance::Bivariant => false, + } + } + + fn create_scope( + &mut self, + value: &ty::Binder>, + universally_quantified: UniversallyQuantified, + ) -> BoundRegionScope<'tcx> { + let mut scope = BoundRegionScope::default(); + + // Create a callback that creates (via the delegate) either an + // existential or placeholder region as needed. + let mut next_region = { + let delegate = &mut self.delegate; + let mut lazy_universe = None; + move |br: ty::BoundRegion| { + if universally_quantified.0 { + // The first time this closure is called, create a + // new universe for the placeholders we will make + // from here out. + let universe = lazy_universe.unwrap_or_else(|| { + let universe = delegate.create_next_universe(); + lazy_universe = Some(universe); + universe + }); + + let placeholder = ty::Placeholder { universe, name: br }; + delegate.next_placeholder_region(placeholder) + } else { + delegate.next_existential_region_var() + } + } + }; + + value.skip_binder().visit_with(&mut ScopeInstantiator { + next_region: &mut next_region, + target_index: ty::INNERMOST, + bound_region_scope: &mut scope, + }); + + scope + } + + /// When we encounter binders during the type traversal, we record + /// the value to substitute for each of the things contained in + /// that binder. (This will be either a universal placeholder or + /// an existential inference variable.) Given the debruijn index + /// `debruijn` (and name `br`) of some binder we have now + /// encountered, this routine finds the value that we instantiated + /// the region with; to do so, it indexes backwards into the list + /// of ambient scopes `scopes`. + fn lookup_bound_region( + debruijn: ty::DebruijnIndex, + br: &ty::BoundRegion, + first_free_index: ty::DebruijnIndex, + scopes: &[BoundRegionScope<'tcx>], + ) -> ty::Region<'tcx> { + // The debruijn index is a "reverse index" into the + // scopes listing. So when we have INNERMOST (0), we + // want the *last* scope pushed, and so forth. + let debruijn_index = debruijn.index() - first_free_index.index(); + let scope = &scopes[scopes.len() - debruijn_index - 1]; + + // Find this bound region in that scope to map to a + // particular region. + scope.map[br] + } + + /// If `r` is a bound region, find the scope in which it is bound + /// (from `scopes`) and return the value that we instantiated it + /// with. Otherwise just return `r`. + fn replace_bound_region( + &self, + r: ty::Region<'tcx>, + first_free_index: ty::DebruijnIndex, + scopes: &[BoundRegionScope<'tcx>], + ) -> ty::Region<'tcx> { + if let ty::ReLateBound(debruijn, br) = r { + Self::lookup_bound_region(*debruijn, br, first_free_index, scopes) + } else { + r + } + } + + /// Push a new outlives requirement into our output set of + /// constraints. + fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { + debug!("push_outlives({:?}: {:?})", sup, sub); + + self.delegate.push_outlives(sup, sub); + } + + /// When we encounter a canonical variable `var` in the output, + /// equate it with `kind`. If the variable has been previously + /// equated, then equate it again. + fn relate_var(&mut self, var_ty: Ty<'tcx>, value_ty: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty); + + let generalized_ty = self.generalize_value(value_ty); + self.infcx + .force_instantiate_unchecked(var_ty, generalized_ty); + + // The generalized values we extract from `canonical_var_values` have + // been fully instantiated and hence the set of scopes we have + // doesn't matter -- just to be sure, put an empty vector + // in there. + let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]); + + // Relate the generalized kind to the original one. + let result = self.relate(&generalized_ty, &value_ty); + + // Restore the old scopes now. + self.a_scopes = old_a_scopes; + + debug!("equate_var: complete, result = {:?}", result); + result + } + + fn generalize_value>(&mut self, value: T) -> T { + TypeGeneralizer { + tcx: self.infcx.tcx, + delegate: &mut self.delegate, + first_free_index: ty::INNERMOST, + ambient_variance: self.ambient_variance, + + // These always correspond to an `_` or `'_` written by + // user, and those are always in the root universe. + universe: ty::UniverseIndex::ROOT, + }.relate(&value, &value) + .unwrap() + } +} + +impl TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D> +where + D: TypeRelatingDelegate<'tcx>, +{ + fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { + self.infcx.tcx + } + + fn tag(&self) -> &'static str { + "nll::subtype" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + variance: ty::Variance, + a: &T, + b: &T, + ) -> RelateResult<'tcx, T> { + debug!( + "relate_with_variance(variance={:?}, a={:?}, b={:?})", + variance, a, b + ); + + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + + debug!( + "relate_with_variance: ambient_variance = {:?}", + self.ambient_variance + ); + + let r = self.relate(a, b)?; + + self.ambient_variance = old_ambient_variance; + + debug!("relate_with_variance: r={:?}", r); + + Ok(r) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + let a = self.infcx.shallow_resolve(a); + match a.sty { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { + self.relate_var(a.into(), b.into()) + } + + _ => { + debug!( + "tys(a={:?}, b={:?}, variance={:?})", + a, b, self.ambient_variance + ); + + relate::super_relate_tys(self, a, b) + } + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug!( + "regions(a={:?}, b={:?}, variance={:?})", + a, b, self.ambient_variance + ); + + let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); + let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); + + debug!("regions: v_a = {:?}", v_a); + debug!("regions: v_b = {:?}", v_b); + + if self.ambient_covariance() { + // Covariance: a <= b. Hence, `b: a`. + self.push_outlives(v_b, v_a); + } + + if self.ambient_contravariance() { + // Contravariant: b <= a. Hence, `a: b`. + self.push_outlives(v_a, v_b); + } + + Ok(a) + } + + fn binders( + &mut self, + a: &ty::Binder, + b: &ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + // We want that + // + // ``` + // for<'a> fn(&'a u32) -> &'a u32 <: + // fn(&'b u32) -> &'b u32 + // ``` + // + // but not + // + // ``` + // fn(&'a u32) -> &'a u32 <: + // for<'b> fn(&'b u32) -> &'b u32 + // ``` + // + // We therefore proceed as follows: + // + // - Instantiate binders on `b` universally, yielding a universe U1. + // - Instantiate binders on `a` existentially in U1. + + debug!( + "binders({:?}: {:?}, ambient_variance={:?})", + a, b, self.ambient_variance + ); + + if self.ambient_covariance() { + // Covariance, so we want `for<..> A <: for<..> B` -- + // therefore we compare any instantiation of A (i.e., A + // instantiated with existentials) against every + // instantiation of B (i.e., B instantiated with + // universals). + + let b_scope = self.create_scope(b, UniversallyQuantified(true)); + let a_scope = self.create_scope(a, UniversallyQuantified(false)); + + debug!("binders: a_scope = {:?} (existential)", a_scope); + debug!("binders: b_scope = {:?} (universal)", b_scope); + + self.b_scopes.push(b_scope); + self.a_scopes.push(a_scope); + + // Reset the ambient variance to covariant. This is needed + // to correctly handle cases like + // + // for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32) + // + // Somewhat surprisingly, these two types are actually + // **equal**, even though the one on the right looks more + // polymorphic. The reason is due to subtyping. To see it, + // consider that each function can call the other: + // + // - The left function can call the right with `'b` and + // `'c` both equal to `'a` + // + // - The right function can call the left with `'a` set to + // `{P}`, where P is the point in the CFG where the call + // itself occurs. Note that `'b` and `'c` must both + // include P. At the point, the call works because of + // subtyping (i.e., `&'b u32 <: &{P} u32`). + let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); + + self.relate(a.skip_binder(), b.skip_binder())?; + + self.ambient_variance = variance; + + self.b_scopes.pop().unwrap(); + self.a_scopes.pop().unwrap(); + } + + if self.ambient_contravariance() { + // Contravariance, so we want `for<..> A :> for<..> B` + // -- therefore we compare every instantiation of A (i.e., + // A instantiated with universals) against any + // instantiation of B (i.e., B instantiated with + // existentials). Opposite of above. + + let a_scope = self.create_scope(a, UniversallyQuantified(true)); + let b_scope = self.create_scope(b, UniversallyQuantified(false)); + + debug!("binders: a_scope = {:?} (universal)", a_scope); + debug!("binders: b_scope = {:?} (existential)", b_scope); + + self.a_scopes.push(a_scope); + self.b_scopes.push(b_scope); + + // Reset ambient variance to contravariance. See the + // covariant case above for an explanation. + let variance = + ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); + + self.relate(a.skip_binder(), b.skip_binder())?; + + self.ambient_variance = variance; + + self.b_scopes.pop().unwrap(); + self.a_scopes.pop().unwrap(); + } + + Ok(a.clone()) + } +} + +/// When we encounter a binder like `for<..> fn(..)`, we actually have +/// to walk the `fn` value to find all the values bound by the `for` +/// (these are not explicitly present in the ty representation right +/// now). This visitor handles that: it descends the type, tracking +/// binder depth, and finds late-bound regions targeting the +/// `for<..`>. For each of those, it creates an entry in +/// `bound_region_scope`. +struct ScopeInstantiator<'me, 'tcx: 'me> { + next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, + // The debruijn index of the scope we are instantiating. + target_index: ty::DebruijnIndex, + bound_region_scope: &'me mut BoundRegionScope<'tcx>, +} + +impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { + fn visit_binder>(&mut self, t: &ty::Binder) -> bool { + self.target_index.shift_in(1); + t.super_visit_with(self); + self.target_index.shift_out(1); + + false + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + let ScopeInstantiator { + bound_region_scope, + next_region, + .. + } = self; + + match r { + ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => { + bound_region_scope + .map + .entry(*br) + .or_insert_with(|| next_region(*br)); + } + + _ => {} + } + + false + } +} + +/// The "type generalize" is used when handling inference variables. +/// +/// The basic strategy for handling a constraint like `?A <: B` is to +/// apply a "generalization strategy" to the type `B` -- this replaces +/// all the lifetimes in the type `B` with fresh inference +/// variables. (You can read more about the strategy in this [blog +/// post].) +/// +/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x +/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the +/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which +/// establishes `'0: 'x` as a constraint. +/// +/// As a side-effect of this generalization procedure, we also replace +/// all the bound regions that we have traversed with concrete values, +/// so that the resulting generalized type is independent from the +/// scopes. +/// +/// [blog post]: https://is.gd/0hKvIr +struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D> +where + D: TypeRelatingDelegate<'tcx> + 'me, +{ + tcx: TyCtxt<'me, 'gcx, 'tcx>, + + delegate: &'me mut D, + + /// After we generalize this type, we are going to relative it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + + first_free_index: ty::DebruijnIndex, + + universe: ty::UniverseIndex, +} + +impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D> +where + D: TypeRelatingDelegate<'tcx>, +{ + fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { + self.tcx + } + + fn tag(&self) -> &'static str { + "nll::generalizer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + variance: ty::Variance, + a: &T, + b: &T, + ) -> RelateResult<'tcx, T> { + debug!( + "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", + variance, a, b + ); + + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + + debug!( + "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", + self.ambient_variance + ); + + let r = self.relate(a, b)?; + + self.ambient_variance = old_ambient_variance; + + debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); + + Ok(r) + } + + fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("TypeGeneralizer::tys(a={:?})", a,); + + match a.sty { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { + bug!( + "unexpected inference variable encountered in NLL generalization: {:?}", + a + ); + } + + _ => relate::super_relate_tys(self, a, a), + } + } + + fn regions( + &mut self, + a: ty::Region<'tcx>, + _: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug!("TypeGeneralizer::regions(a={:?})", a,); + + if let ty::ReLateBound(debruijn, _) = a { + if *debruijn < self.first_free_index { + return Ok(a); + } + } + + // For now, we just always create a fresh region variable to + // replace all the regions in the source type. In the main + // type checker, we special case the case where the ambient + // variance is `Invariant` and try to avoid creating a fresh + // region variable, but since this comes up so much less in + // NLL (only when users use `_` etc) it is much less + // important. + // + // As an aside, since these new variables are created in + // `self.universe` universe, this also serves to enforce the + // universe scoping rules. + // + // FIXME(#54105) -- if the ambient variance is bivariant, + // though, we may however need to check well-formedness or + // risk a problem like #41677 again. + + let replacement_region_vid = self.delegate.generalize_existential(self.universe); + + Ok(replacement_region_vid) + } + + fn binders( + &mut self, + a: &ty::Binder, + _: &ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + debug!("TypeGeneralizer::binders(a={:?})", a,); + + self.first_free_index.shift_in(1); + let result = self.relate(a.skip_binder(), a.skip_binder())?; + self.first_free_index.shift_out(1); + Ok(ty::Binder::bind(result)) + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 26cd939a4da..99e47663997 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -11,14 +11,12 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; use rustc::mir::ConstraintCategory; use rustc::traits::query::Fallible; -use rustc::ty::fold::{TypeFoldable, TypeVisitor}; -use rustc::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc::ty::subst::Kind; -use rustc::ty::{self, CanonicalTy, Ty, TyCtxt}; -use rustc_data_structures::fx::FxHashMap; -use syntax::source_map::DUMMY_SP; +use rustc::ty::relate::TypeRelation; +use rustc::ty::{self, CanonicalTy, Ty}; +use syntax_pos::DUMMY_SP; /// Adds sufficient constraints to ensure that `a <: b`. pub(super) fn sub_types<'tcx>( @@ -93,78 +91,6 @@ pub(super) fn relate_type_and_user_type<'tcx>( Ok(b) } -struct TypeRelating<'me, 'gcx: 'tcx, 'tcx: 'me, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, - - /// Callback to use when we deduce an outlives relationship - delegate: D, - - /// How are we relating `a` and `b`? - /// - /// - covariant means `a <: b` - /// - contravariant means `b <: a` - /// - invariant means `a == b - /// - bivariant means that it doesn't matter - ambient_variance: ty::Variance, - - /// When we pass through a set of binders (e.g., when looking into - /// a `fn` type), we push a new bound region scope onto here. This - /// will contain the instantiated region for each region in those - /// binders. When we then encounter a `ReLateBound(d, br)`, we can - /// use the debruijn index `d` to find the right scope, and then - /// bound region name `br` to find the specific instantiation from - /// within that scope. See `replace_bound_region`. - /// - /// This field stores the instantiations for late-bound regions in - /// the `a` type. - a_scopes: Vec>, - - /// Same as `a_scopes`, but for the `b` type. - b_scopes: Vec>, -} - -trait TypeRelatingDelegate<'tcx> { - /// Push a constraint `sup: sub` -- this constraint must be - /// satisfied for the two types to be related. `sub` and `sup` may - /// be regions from the type or new variables created through the - /// delegate. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>); - - /// Creates a new universe index. Used when instantiating placeholders. - fn create_next_universe(&mut self) -> ty::UniverseIndex; - - /// Creates a new region variable representing a higher-ranked - /// region that is instantiated existentially. This creates an - /// inference variable, typically. - /// - /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'a` with an - /// inference variable (though `'b` would be instantiated first, - /// as a placeholder). - fn next_existential_region_var(&mut self) -> ty::Region<'tcx>; - - /// Creates a new region variable representing a - /// higher-ranked region that is instantiated universally. - /// This creates a new region placeholder, typically. - /// - /// So e.g. if you have `for<'a> fn(..) <: for<'b> fn(..)`, then - /// we will invoke this method to instantiate `'b` with a - /// placeholder region. - fn next_placeholder_region(&mut self, placeholder: ty::Placeholder) -> ty::Region<'tcx>; - - /// Creates a new existential region in the given universe. This - /// is used when handling subtyping and type variables -- if we - /// have that `?X <: Foo<'a>`, for example, we would instantiate - /// `?X` with a type like `Foo<'?0>` where `'?0` is a fresh - /// existential variable created by this function. We would then - /// relate `Foo<'?0>` with `Foo<'a>` (and probably add an outlives - /// relation stating that `'?0: 'a`). - fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; -} - struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> { infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, borrowck_context: Option<&'me mut BorrowCheckContext<'bccx, 'tcx>>, @@ -231,575 +157,3 @@ impl TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, '_, 'tcx> { } } } - -#[derive(Clone, Debug)] -struct ScopesAndKind<'tcx> { - scopes: Vec>, - kind: Kind<'tcx>, -} - -#[derive(Clone, Debug, Default)] -struct BoundRegionScope<'tcx> { - map: FxHashMap>, -} - -#[derive(Copy, Clone)] -struct UniversallyQuantified(bool); - -impl<'me, 'gcx, 'tcx, D> TypeRelating<'me, 'gcx, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn new( - infcx: &'me InferCtxt<'me, 'gcx, 'tcx>, - delegate: D, - ambient_variance: ty::Variance, - ) -> Self { - Self { - infcx, - delegate, - ambient_variance, - a_scopes: vec![], - b_scopes: vec![], - } - } - - fn ambient_covariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Covariant | ty::Variance::Invariant => true, - ty::Variance::Contravariant | ty::Variance::Bivariant => false, - } - } - - fn ambient_contravariance(&self) -> bool { - match self.ambient_variance { - ty::Variance::Contravariant | ty::Variance::Invariant => true, - ty::Variance::Covariant | ty::Variance::Bivariant => false, - } - } - - fn create_scope( - &mut self, - value: &ty::Binder>, - universally_quantified: UniversallyQuantified, - ) -> BoundRegionScope<'tcx> { - let mut scope = BoundRegionScope::default(); - - // Create a callback that creates (via the delegate) either an - // existential or placeholder region as needed. - let mut next_region = { - let delegate = &mut self.delegate; - let mut lazy_universe = None; - move |br: ty::BoundRegion| { - if universally_quantified.0 { - // The first time this closure is called, create a - // new universe for the placeholders we will make - // from here out. - let universe = lazy_universe.unwrap_or_else(|| { - let universe = delegate.create_next_universe(); - lazy_universe = Some(universe); - universe - }); - - let placeholder = ty::Placeholder { universe, name: br }; - delegate.next_placeholder_region(placeholder) - } else { - delegate.next_existential_region_var() - } - } - }; - - value.skip_binder().visit_with(&mut ScopeInstantiator { - next_region: &mut next_region, - target_index: ty::INNERMOST, - bound_region_scope: &mut scope, - }); - - scope - } - - /// When we encounter binders during the type traversal, we record - /// the value to substitute for each of the things contained in - /// that binder. (This will be either a universal placeholder or - /// an existential inference variable.) Given the debruijn index - /// `debruijn` (and name `br`) of some binder we have now - /// encountered, this routine finds the value that we instantiated - /// the region with; to do so, it indexes backwards into the list - /// of ambient scopes `scopes`. - fn lookup_bound_region( - debruijn: ty::DebruijnIndex, - br: &ty::BoundRegion, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - // The debruijn index is a "reverse index" into the - // scopes listing. So when we have INNERMOST (0), we - // want the *last* scope pushed, and so forth. - let debruijn_index = debruijn.index() - first_free_index.index(); - let scope = &scopes[scopes.len() - debruijn_index - 1]; - - // Find this bound region in that scope to map to a - // particular region. - scope.map[br] - } - - /// If `r` is a bound region, find the scope in which it is bound - /// (from `scopes`) and return the value that we instantiated it - /// with. Otherwise just return `r`. - fn replace_bound_region( - &self, - r: ty::Region<'tcx>, - first_free_index: ty::DebruijnIndex, - scopes: &[BoundRegionScope<'tcx>], - ) -> ty::Region<'tcx> { - if let ty::ReLateBound(debruijn, br) = r { - Self::lookup_bound_region(*debruijn, br, first_free_index, scopes) - } else { - r - } - } - - /// Push a new outlives requirement into our output set of - /// constraints. - fn push_outlives(&mut self, sup: ty::Region<'tcx>, sub: ty::Region<'tcx>) { - debug!("push_outlives({:?}: {:?})", sup, sub); - - self.delegate.push_outlives(sup, sub); - } - - /// When we encounter a canonical variable `var` in the output, - /// equate it with `kind`. If the variable has been previously - /// equated, then equate it again. - fn relate_var( - &mut self, - var_ty: Ty<'tcx>, - value_ty: Ty<'tcx>, - ) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("equate_var(var_ty={:?}, value_ty={:?})", var_ty, value_ty); - - let generalized_ty = self.generalize_value(value_ty); - self.infcx.force_instantiate_unchecked(var_ty, generalized_ty); - - // The generalized values we extract from `canonical_var_values` have - // been fully instantiated and hence the set of scopes we have - // doesn't matter -- just to be sure, put an empty vector - // in there. - let old_a_scopes = ::std::mem::replace(&mut self.a_scopes, vec![]); - - // Relate the generalized kind to the original one. - let result = self.relate(&generalized_ty, &value_ty); - - // Restore the old scopes now. - self.a_scopes = old_a_scopes; - - debug!("equate_var: complete, result = {:?}", result); - result - } - - fn generalize_value>(&mut self, value: T) -> T { - TypeGeneralizer { - tcx: self.infcx.tcx, - delegate: &mut self.delegate, - first_free_index: ty::INNERMOST, - ambient_variance: self.ambient_variance, - - // These always correspond to an `_` or `'_` written by - // user, and those are always in the root universe. - universe: ty::UniverseIndex::ROOT, - }.relate(&value, &value) - .unwrap() - } -} - -impl TypeRelation<'me, 'gcx, 'tcx> for TypeRelating<'me, 'gcx, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { - self.infcx.tcx - } - - fn tag(&self) -> &'static str { - "nll::subtype" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - debug!( - "relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - let a = self.infcx.shallow_resolve(a); - match a.sty { - ty::Infer(ty::TyVar(_)) | - ty::Infer(ty::IntVar(_)) | - ty::Infer(ty::FloatVar(_)) => { - self.relate_var(a.into(), b.into()) - } - - _ => { - debug!( - "tys(a={:?}, b={:?}, variance={:?})", - a, b, self.ambient_variance - ); - - relate::super_relate_tys(self, a, b) - } - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!( - "regions(a={:?}, b={:?}, variance={:?})", - a, b, self.ambient_variance - ); - - let v_a = self.replace_bound_region(a, ty::INNERMOST, &self.a_scopes); - let v_b = self.replace_bound_region(b, ty::INNERMOST, &self.b_scopes); - - debug!("regions: v_a = {:?}", v_a); - debug!("regions: v_b = {:?}", v_b); - - if self.ambient_covariance() { - // Covariance: a <= b. Hence, `b: a`. - self.push_outlives(v_b, v_a); - } - - if self.ambient_contravariance() { - // Contravariant: b <= a. Hence, `a: b`. - self.push_outlives(v_a, v_b); - } - - Ok(a) - } - - fn binders( - &mut self, - a: &ty::Binder, - b: &ty::Binder, - ) -> RelateResult<'tcx, ty::Binder> - where - T: Relate<'tcx>, - { - // We want that - // - // ``` - // for<'a> fn(&'a u32) -> &'a u32 <: - // fn(&'b u32) -> &'b u32 - // ``` - // - // but not - // - // ``` - // fn(&'a u32) -> &'a u32 <: - // for<'b> fn(&'b u32) -> &'b u32 - // ``` - // - // We therefore proceed as follows: - // - // - Instantiate binders on `b` universally, yielding a universe U1. - // - Instantiate binders on `a` existentially in U1. - - debug!( - "binders({:?}: {:?}, ambient_variance={:?})", - a, b, self.ambient_variance - ); - - if self.ambient_covariance() { - // Covariance, so we want `for<..> A <: for<..> B` -- - // therefore we compare any instantiation of A (i.e., A - // instantiated with existentials) against every - // instantiation of B (i.e., B instantiated with - // universals). - - let b_scope = self.create_scope(b, UniversallyQuantified(true)); - let a_scope = self.create_scope(a, UniversallyQuantified(false)); - - debug!("binders: a_scope = {:?} (existential)", a_scope); - debug!("binders: b_scope = {:?} (universal)", b_scope); - - self.b_scopes.push(b_scope); - self.a_scopes.push(a_scope); - - // Reset the ambient variance to covariant. This is needed - // to correctly handle cases like - // - // for<'a> fn(&'a u32, &'a u3) == for<'b, 'c> fn(&'b u32, &'c u32) - // - // Somewhat surprisingly, these two types are actually - // **equal**, even though the one on the right looks more - // polymorphic. The reason is due to subtyping. To see it, - // consider that each function can call the other: - // - // - The left function can call the right with `'b` and - // `'c` both equal to `'a` - // - // - The right function can call the left with `'a` set to - // `{P}`, where P is the point in the CFG where the call - // itself occurs. Note that `'b` and `'c` must both - // include P. At the point, the call works because of - // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); - - self.relate(a.skip_binder(), b.skip_binder())?; - - self.ambient_variance = variance; - - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); - } - - if self.ambient_contravariance() { - // Contravariance, so we want `for<..> A :> for<..> B` - // -- therefore we compare every instantiation of A (i.e., - // A instantiated with universals) against any - // instantiation of B (i.e., B instantiated with - // existentials). Opposite of above. - - let a_scope = self.create_scope(a, UniversallyQuantified(true)); - let b_scope = self.create_scope(b, UniversallyQuantified(false)); - - debug!("binders: a_scope = {:?} (universal)", a_scope); - debug!("binders: b_scope = {:?} (existential)", b_scope); - - self.a_scopes.push(a_scope); - self.b_scopes.push(b_scope); - - // Reset ambient variance to contravariance. See the - // covariant case above for an explanation. - let variance = - ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); - - self.relate(a.skip_binder(), b.skip_binder())?; - - self.ambient_variance = variance; - - self.b_scopes.pop().unwrap(); - self.a_scopes.pop().unwrap(); - } - - Ok(a.clone()) - } -} - -/// When we encounter a binder like `for<..> fn(..)`, we actually have -/// to walk the `fn` value to find all the values bound by the `for` -/// (these are not explicitly present in the ty representation right -/// now). This visitor handles that: it descends the type, tracking -/// binder depth, and finds late-bound regions targeting the -/// `for<..`>. For each of those, it creates an entry in -/// `bound_region_scope`. -struct ScopeInstantiator<'me, 'tcx: 'me> { - next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>, - // The debruijn index of the scope we are instantiating. - target_index: ty::DebruijnIndex, - bound_region_scope: &'me mut BoundRegionScope<'tcx>, -} - -impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> { - fn visit_binder>(&mut self, t: &ty::Binder) -> bool { - self.target_index.shift_in(1); - t.super_visit_with(self); - self.target_index.shift_out(1); - - false - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - let ScopeInstantiator { - bound_region_scope, - next_region, - .. - } = self; - - match r { - ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => { - bound_region_scope - .map - .entry(*br) - .or_insert_with(|| next_region(*br)); - } - - _ => {} - } - - false - } -} - -/// The "type generalize" is used when handling inference variables. -/// -/// The basic strategy for handling a constraint like `?A <: B` is to -/// apply a "generalization strategy" to the type `B` -- this replaces -/// all the lifetimes in the type `B` with fresh inference -/// variables. (You can read more about the strategy in this [blog -/// post].) -/// -/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x -/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the -/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which -/// establishes `'0: 'x` as a constraint. -/// -/// As a side-effect of this generalization procedure, we also replace -/// all the bound regions that we have traversed with concrete values, -/// so that the resulting generalized type is independent from the -/// scopes. -/// -/// [blog post]: https://is.gd/0hKvIr -struct TypeGeneralizer<'me, 'gcx: 'tcx, 'tcx: 'me, D> -where - D: TypeRelatingDelegate<'tcx> + 'me, -{ - tcx: TyCtxt<'me, 'gcx, 'tcx>, - - delegate: &'me mut D, - - /// After we generalize this type, we are going to relative it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - - first_free_index: ty::DebruijnIndex, - - universe: ty::UniverseIndex, -} - -impl TypeRelation<'me, 'gcx, 'tcx> for TypeGeneralizer<'me, 'gcx, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'me, 'gcx, 'tcx> { - self.tcx - } - - fn tag(&self) -> &'static str { - "nll::generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance>( - &mut self, - variance: ty::Variance, - a: &T, - b: &T, - ) -> RelateResult<'tcx, T> { - debug!( - "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - debug!("TypeGeneralizer::tys(a={:?})", a,); - - match a.sty { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) => { - bug!( - "unexpected inference variable encountered in NLL generalization: {:?}", - a - ); - } - - _ => relate::super_relate_tys(self, a, a), - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a,); - - if let ty::ReLateBound(debruijn, _) = a { - if *debruijn < self.first_free_index { - return Ok(a); - } - } - - // For now, we just always create a fresh region variable to - // replace all the regions in the source type. In the main - // type checker, we special case the case where the ambient - // variance is `Invariant` and try to avoid creating a fresh - // region variable, but since this comes up so much less in - // NLL (only when users use `_` etc) it is much less - // important. - // - // As an aside, since these new variables are created in - // `self.universe` universe, this also serves to enforce the - // universe scoping rules. - // - // FIXME(#54105) -- if the ambient variance is bivariant, - // though, we may however need to check well-formedness or - // risk a problem like #41677 again. - - let replacement_region_vid = self.delegate.generalize_existential(self.universe); - - Ok(replacement_region_vid) - } - - fn binders( - &mut self, - a: &ty::Binder, - _: &ty::Binder, - ) -> RelateResult<'tcx, ty::Binder> - where - T: Relate<'tcx>, - { - debug!("TypeGeneralizer::binders(a={:?})", a,); - - self.first_free_index.shift_in(1); - let result = self.relate(a.skip_binder(), a.skip_binder())?; - self.first_free_index.shift_out(1); - Ok(ty::Binder::bind(result)) - } -} From e339e84fffb3156aaa78fbf686436de02ba4cf48 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 15:34:23 -0400 Subject: [PATCH 07/19] move `force_instantiate_unchecked` to be local to `nll_relate` code --- src/librustc/infer/mod.rs | 59 --------------------------- src/librustc/infer/nll_relate/mod.rs | 61 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 59 deletions(-) diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index 9d56cf5aabe..fbd38ebd78c 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1231,65 +1231,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.inlined_shallow_resolve(typ) } - /// A hacky sort of method used by the NLL type-relating code: - /// - /// - `var` must be some unbound type variable. - /// - `value` must be a suitable type to use as its value. - /// - /// `var` will then be equated with `value`. Note that this - /// sidesteps a number of important checks, such as the "occurs - /// check" that prevents cyclic types, so it is important not to - /// use this method during regular type-check. - fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { - match (&var.sty, &value.sty) { - (&ty::Infer(ty::TyVar(vid)), _) => { - let mut type_variables = self.type_variables.borrow_mut(); - - // In NLL, we don't have type inference variables - // floating around, so we can do this rather imprecise - // variant of the occurs-check. - assert!(!value.has_infer_types()); - - type_variables.instantiate(vid, value); - } - - (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - int_unification_table - .unify_var_value(vid, Some(ty::IntVarValue::IntType(value))) - .unwrap_or_else(|_| { - bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); - }); - } - - (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - int_unification_table - .unify_var_value(vid, Some(ty::IntVarValue::UintType(value))) - .unwrap_or_else(|_| { - bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); - }); - } - - (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => { - let mut float_unification_table = self.float_unification_table.borrow_mut(); - float_unification_table - .unify_var_value(vid, Some(ty::FloatVarValue(value))) - .unwrap_or_else(|_| { - bug!("failed to unify float var `{:?}` with `{:?}`", vid, value) - }); - } - - _ => { - bug!( - "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}", - var, - value, - ); - } - } - } - pub fn resolve_type_vars_if_possible(&self, value: &T) -> T where T: TypeFoldable<'tcx>, diff --git a/src/librustc/infer/nll_relate/mod.rs b/src/librustc/infer/nll_relate/mod.rs index bd126b17971..e003c1989e0 100644 --- a/src/librustc/infer/nll_relate/mod.rs +++ b/src/librustc/infer/nll_relate/mod.rs @@ -673,3 +673,64 @@ where Ok(ty::Binder::bind(result)) } } + +impl InferCtxt<'_, '_, 'tcx> { + /// A hacky sort of method used by the NLL type-relating code: + /// + /// - `var` must be some unbound type variable. + /// - `value` must be a suitable type to use as its value. + /// + /// `var` will then be equated with `value`. Note that this + /// sidesteps a number of important checks, such as the "occurs + /// check" that prevents cyclic types, so it is important not to + /// use this method during regular type-check. + fn force_instantiate_unchecked(&self, var: Ty<'tcx>, value: Ty<'tcx>) { + match (&var.sty, &value.sty) { + (&ty::Infer(ty::TyVar(vid)), _) => { + let mut type_variables = self.type_variables.borrow_mut(); + + // In NLL, we don't have type inference variables + // floating around, so we can do this rather imprecise + // variant of the occurs-check. + assert!(!value.has_infer_types()); + + type_variables.instantiate(vid, value); + } + + (&ty::Infer(ty::IntVar(vid)), &ty::Int(value)) => { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + int_unification_table + .unify_var_value(vid, Some(ty::IntVarValue::IntType(value))) + .unwrap_or_else(|_| { + bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); + }); + } + + (&ty::Infer(ty::IntVar(vid)), &ty::Uint(value)) => { + let mut int_unification_table = self.int_unification_table.borrow_mut(); + int_unification_table + .unify_var_value(vid, Some(ty::IntVarValue::UintType(value))) + .unwrap_or_else(|_| { + bug!("failed to unify int var `{:?}` with `{:?}`", vid, value); + }); + } + + (&ty::Infer(ty::FloatVar(vid)), &ty::Float(value)) => { + let mut float_unification_table = self.float_unification_table.borrow_mut(); + float_unification_table + .unify_var_value(vid, Some(ty::FloatVarValue(value))) + .unwrap_or_else(|_| { + bug!("failed to unify float var `{:?}` with `{:?}`", vid, value) + }); + } + + _ => { + bug!( + "force_instantiate_unchecked invoked with bad combination: var={:?} value={:?}", + var, + value, + ); + } + } + } +} From aed6e4a0834d11cad0bf5e1ebe065eabff1f405c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 17:07:10 -0400 Subject: [PATCH 08/19] introduce a `UserTypeAnnotation` enum --- src/librustc/ich/impls_mir.rs | 13 +++++ src/librustc/mir/mod.rs | 24 ++++++++-- src/librustc/mir/visit.rs | 22 ++++----- .../borrow_check/nll/constraint_generation.rs | 5 +- src/librustc_mir/borrow_check/nll/renumber.rs | 10 ++-- .../borrow_check/nll/type_check/mod.rs | 6 +-- .../borrow_check/nll/type_check/relate_tys.rs | 19 ++++---- src/librustc_mir/build/matches/mod.rs | 10 ++-- src/librustc_mir/hair/cx/block.rs | 4 +- src/librustc_mir/hair/cx/expr.rs | 27 ++++++----- src/librustc_mir/hair/mod.rs | 18 +++---- src/librustc_mir/hair/pattern/mod.rs | 8 ++-- src/librustc_mir/hair/util.rs | 48 +++++++++++-------- 13 files changed, 126 insertions(+), 88 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 337cc0fc627..38a298d81dd 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -587,3 +587,16 @@ impl<'a, 'gcx> HashStable> for mir::ClosureOutlivesSubj } impl_stable_hash_for!(struct mir::interpret::GlobalId<'tcx> { instance, promoted }); + +impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation<'gcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + mir::UserTypeAnnotation::Ty(ref ty) => { + ty.hash_stable(hcx, hasher); + } + } + } +} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 2587e19b1cb..eb4aa7ece49 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -710,7 +710,7 @@ pub struct LocalDecl<'tcx> { /// e.g. via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. - pub user_ty: Option<(CanonicalTy<'tcx>, Span)>, + pub user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, /// Name of the local, used in debuginfo and pretty-printing. /// @@ -1737,7 +1737,7 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>), + AscribeUserType(Place<'tcx>, ty::Variance, UserTypeAnnotation<'tcx>), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -2188,7 +2188,7 @@ pub enum AggregateKind<'tcx> { &'tcx AdtDef, usize, &'tcx Substs<'tcx>, - Option>, + Option>, Option, ), @@ -2392,7 +2392,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// this does not necessarily mean that they are "==" in Rust -- in /// particular one must be wary of `NaN`! -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub struct Constant<'tcx> { pub span: Span, pub ty: Ty<'tcx>, @@ -2402,11 +2402,25 @@ pub struct Constant<'tcx> { /// indicate that `Vec<_>` was explicitly specified. /// /// Needed for NLL to impose user-given type constraints. - pub user_ty: Option>, + pub user_ty: Option>, pub literal: &'tcx ty::Const<'tcx>, } +/// A user-given type annotation attached to a constant. These arise +/// from constants that are named via paths, like `Foo::::new` and +/// so forth. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub enum UserTypeAnnotation<'tcx> { + Ty(CanonicalTy<'tcx>), +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { + (UserTypeAnnotation::Ty)(ty), + } +} + newtype_index! { pub struct Promoted { DEBUG_FORMAT = "promoted[{}]" diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 920dc88d6a8..3e92b1fd7ce 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::subst::Substs; -use ty::{CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty}; +use ty::{ClosureSubsts, GeneratorSubsts, Region, Ty}; use mir::*; use syntax_pos::Span; @@ -147,9 +147,9 @@ macro_rules! make_mir_visitor { fn visit_ascribe_user_ty(&mut self, place: & $($mutability)* Place<'tcx>, variance: & $($mutability)* ty::Variance, - c_ty: & $($mutability)* CanonicalTy<'tcx>, + user_ty: & $($mutability)* UserTypeAnnotation<'tcx>, location: Location) { - self.super_ascribe_user_ty(place, variance, c_ty, location); + self.super_ascribe_user_ty(place, variance, user_ty, location); } fn visit_place(&mut self, @@ -214,8 +214,8 @@ macro_rules! make_mir_visitor { self.super_ty(ty); } - fn visit_user_ty(&mut self, ty: & $($mutability)* CanonicalTy<'tcx>) { - self.super_canonical_ty(ty); + fn visit_user_type_annotation(&mut self, ty: & $($mutability)* UserTypeAnnotation<'tcx>) { + self.super_user_type_annotation(ty); } fn visit_region(&mut self, @@ -390,9 +390,9 @@ macro_rules! make_mir_visitor { StatementKind::AscribeUserType( ref $($mutability)* place, ref $($mutability)* variance, - ref $($mutability)* c_ty, + ref $($mutability)* user_ty, ) => { - self.visit_ascribe_user_ty(place, variance, c_ty, location); + self.visit_ascribe_user_ty(place, variance, user_ty, location); } StatementKind::Nop => {} } @@ -637,10 +637,10 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)* Place<'tcx>, _variance: & $($mutability)* ty::Variance, - c_ty: & $($mutability)* CanonicalTy<'tcx>, + user_ty: & $($mutability)* UserTypeAnnotation<'tcx>, location: Location) { self.visit_place(place, PlaceContext::Validate, location); - self.visit_user_ty(c_ty); + self.visit_user_type_annotation(user_ty); } fn super_place(&mut self, @@ -736,7 +736,7 @@ macro_rules! make_mir_visitor { source_info: *source_info, }); if let Some((user_ty, _)) = user_ty { - self.visit_user_ty(user_ty); + self.visit_user_type_annotation(user_ty); } self.visit_source_info(source_info); self.visit_source_scope(visibility_scope); @@ -783,7 +783,7 @@ macro_rules! make_mir_visitor { self.visit_source_scope(scope); } - fn super_canonical_ty(&mut self, _ty: & $($mutability)* CanonicalTy<'tcx>) { + fn super_user_type_annotation(&mut self, _ty: & $($mutability)* UserTypeAnnotation<'tcx>) { } fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 7e8e1b32d4d..30b263a923a 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -18,9 +18,10 @@ use rustc::mir::visit::TyContext; use rustc::mir::visit::Visitor; use rustc::mir::{BasicBlock, BasicBlockData, Location, Mir, Place, Rvalue}; use rustc::mir::{Statement, Terminator}; +use rustc::mir::UserTypeAnnotation; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::Substs; -use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, RegionVid}; +use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid}; pub(super) fn generate_constraints<'cx, 'gcx, 'tcx>( infcx: &InferCtxt<'cx, 'gcx, 'tcx>, @@ -179,7 +180,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx &mut self, _place: &Place<'tcx>, _variance: &ty::Variance, - _c_ty: &CanonicalTy<'tcx>, + _user_ty: &UserTypeAnnotation<'tcx>, _location: Location, ) { } diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 15a60badc93..363afb87ed9 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -9,8 +9,8 @@ // except according to those terms. use rustc::ty::subst::Substs; -use rustc::ty::{self, CanonicalTy, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; -use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind}; +use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, Ty, TypeFoldable}; +use rustc::mir::{BasicBlock, Location, Mir, Statement, StatementKind, UserTypeAnnotation}; use rustc::mir::visit::{MutVisitor, TyContext}; use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; @@ -65,12 +65,12 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> { debug!("visit_ty: ty={:?}", ty); } - fn visit_user_ty(&mut self, _ty: &mut CanonicalTy<'tcx>) { - // `user_ty` annotations represent the types that the user + fn visit_user_type_annotation(&mut self, _ty: &mut UserTypeAnnotation<'tcx>) { + // User type annotations represent the types that the user // wrote in the progarm. We don't want to erase the regions // from these types: rather, we want to add them as // constraints at type-check time. - debug!("visit_user_ty: skipping renumber"); + debug!("visit_user_type_annotation: skipping renumber"); } fn visit_substs(&mut self, substs: &mut &'tcx Substs<'tcx>, location: Location) { 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 e11f452e16b..1e79bc272e4 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -43,7 +43,7 @@ use rustc::traits::query::{Fallible, NoSolution}; use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::ty::fold::TypeFoldable; use rustc::ty::subst::{Subst, UnpackedKind}; -use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; +use rustc::ty::{self, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; use std::rc::Rc; use std::{fmt, iter}; use syntax_pos::{Span, DUMMY_SP}; @@ -966,7 +966,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, a: Ty<'tcx>, v: ty::Variance, - b: CanonicalTy<'tcx>, + b: UserTypeAnnotation<'tcx>, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { @@ -1837,7 +1837,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { /// If this rvalue supports a user-given type annotation, then /// extract and return it. This represents the final type of the /// rvalue and will be unified with the inferred type. - fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option> { + fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option> { match rvalue { Rvalue::Use(_) | Rvalue::Repeat(..) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 99e47663997..35d0b96b88a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -10,12 +10,12 @@ use borrow_check::nll::constraints::OutlivesConstraint; use borrow_check::nll::type_check::{BorrowCheckContext, Locations}; -use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::infer::nll_relate::{TypeRelating, TypeRelatingDelegate}; -use rustc::mir::ConstraintCategory; +use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; +use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; use rustc::traits::query::Fallible; use rustc::ty::relate::TypeRelation; -use rustc::ty::{self, CanonicalTy, Ty}; +use rustc::ty::{self, Ty}; use syntax_pos::DUMMY_SP; /// Adds sufficient constraints to ensure that `a <: b`. @@ -61,20 +61,21 @@ pub(super) fn relate_type_and_user_type<'tcx>( infcx: &InferCtxt<'_, '_, 'tcx>, a: Ty<'tcx>, v: ty::Variance, - canonical_b: CanonicalTy<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, locations: Locations, category: ConstraintCategory, borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>, ) -> Fallible> { debug!( "relate_type_and_user_type(a={:?}, v={:?}, b={:?}, locations={:?})", - a, v, canonical_b, locations + a, v, user_ty, locations ); - let (b, _values) = infcx.instantiate_canonical_with_fresh_inference_vars( - DUMMY_SP, - &canonical_b, - ); + let (b, _values) = match user_ty { + UserTypeAnnotation::Ty(canonical_ty) => { + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty) + } + }; // The `TypeRelating` code assumes that the "canonical variables" // appear in the "a" side, so flip `Contravariant` ambient diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index 394fa4e077c..99c0a52a8ee 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -20,7 +20,7 @@ use build::{GuardFrame, GuardFrameLocal, LocalsForNode}; use hair::*; use rustc::hir; use rustc::mir::*; -use rustc::ty::{self, CanonicalTy, Ty}; +use rustc::ty::{self, Ty}; use rustc_data_structures::bit_set::BitSet; use rustc_data_structures::fx::FxHashMap; use syntax::ast::{Name, NodeId}; @@ -491,7 +491,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - mut pattern_user_ty: Option<(CanonicalTy<'tcx>, Span)>, + mut pattern_user_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, f: &mut impl FnMut( &mut Self, Mutability, @@ -500,7 +500,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { NodeId, Span, Ty<'tcx>, - Option<(CanonicalTy<'tcx>, Span)>, + Option<(UserTypeAnnotation<'tcx>, Span)>, ), ) { match *pattern.kind { @@ -626,7 +626,7 @@ struct Binding<'tcx> { struct Ascription<'tcx> { span: Span, source: Place<'tcx>, - user_ty: CanonicalTy<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, } #[derive(Clone, Debug)] @@ -1470,7 +1470,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { num_patterns: usize, var_id: NodeId, var_ty: Ty<'tcx>, - user_var_ty: Option<(CanonicalTy<'tcx>, Span)>, + user_var_ty: Option<(UserTypeAnnotation<'tcx>, Span)>, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index 022c606a0f8..9865867a196 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -86,12 +86,12 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let mut pattern = cx.pattern_from_hir(&local.pat); if let Some(ty) = &local.ty { - if let Some(user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { + if let Some(&user_ty) = cx.tables.user_provided_tys().get(ty.hir_id) { pattern = Pattern { ty: pattern.ty, span: pattern.span, kind: Box::new(PatternKind::AscribeUserType { - user_ty: *user_ty, + user_ty: UserTypeAnnotation::Ty(user_ty), user_ty_span: ty.span, subpattern: pattern }) diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 813400422db..4dc43a533cf 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -296,11 +296,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = cx.tables().user_substs(fun.hir_id) .map(|user_substs| { - user_substs.unchecked_map(|user_substs| { + UserTypeAnnotation::Ty(user_substs.unchecked_map(|user_substs| { // Here, we just pair an `AdtDef` with the // `user_substs`, so no new types etc are introduced. cx.tcx().mk_adt(adt_def, user_substs) - }) + })) }); let field_refs = args.iter() @@ -725,9 +725,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } hir::ExprKind::Type(ref source, ref ty) => { let user_provided_tys = cx.tables.user_provided_tys(); - let user_ty = *user_provided_tys - .get(ty.hir_id) - .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source)); + let user_ty = UserTypeAnnotation::Ty( + *user_provided_tys + .get(ty.hir_id) + .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source)) + ); if source.is_place_expr() { ExprKind::PlaceTypeAscription { source: source.to_ref(), @@ -763,7 +765,7 @@ fn user_substs_applied_to_def( cx: &mut Cx<'a, 'gcx, 'tcx>, hir_id: hir::HirId, def: &Def, -) -> Option> { +) -> Option> { match def { // A reference to something callable -- e.g., a fn, method, or // a tuple-struct or tuple-variant. This has the type of a @@ -772,11 +774,14 @@ fn user_substs_applied_to_def( Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => - Some(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| { - // Here, we just pair a `DefId` with the - // `user_substs`, so no new types etc are introduced. - cx.tcx().mk_fn_def(def.def_id(), user_substs) - })), + Some( + UserTypeAnnotation::Ty(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| { + // Here, we just pair a `DefId` with the + // `user_substs`, so no new types etc are introduced. + cx.tcx().mk_fn_def(def.def_id(), user_substs) + }), + ) + ), Def::Const(_def_id) | Def::AssociatedConst(_def_id) => diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index e4f88e4fcc3..781b6c92aa1 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -14,11 +14,11 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc::mir::{BinOp, BorrowKind, Field, UnOp}; +use rustc::mir::{BinOp, BorrowKind, UserTypeAnnotation, Field, UnOp}; use rustc::hir::def_id::DefId; use rustc::middle::region; use rustc::ty::subst::Substs; -use rustc::ty::{AdtDef, CanonicalTy, UpvarSubsts, Region, Ty, Const}; +use rustc::ty::{AdtDef, UpvarSubsts, Region, Ty, Const}; use rustc::hir; use syntax::ast; use syntax_pos::Span; @@ -268,7 +268,7 @@ pub enum ExprKind<'tcx> { /// Optional user-given substs: for something like `let x = /// Bar:: { ... }`. - user_ty: Option>, + user_ty: Option>, fields: Vec>, base: Option> @@ -276,12 +276,12 @@ pub enum ExprKind<'tcx> { PlaceTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: CanonicalTy<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, }, ValueTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression - user_ty: CanonicalTy<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, }, Closure { closure_id: DefId, @@ -291,13 +291,7 @@ pub enum ExprKind<'tcx> { }, Literal { literal: &'tcx Const<'tcx>, - - /// Optional user-given type: for something like - /// `collect::>`, this would be present and would - /// indicate that `Vec<_>` was explicitly specified. - /// - /// Needed for NLL to impose user-given type constraints. - user_ty: Option>, + user_ty: Option>, }, InlineAsm { asm: &'tcx hir::InlineAsm, diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 0238a23895e..cb974366a30 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -20,9 +20,9 @@ use const_eval::{const_field, const_variant_index}; use hair::util::UserAnnotatedTyHelpers; -use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; +use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability, UserTypeAnnotation}; use rustc::mir::interpret::{Scalar, GlobalId, ConstValue, sign_extend}; -use rustc::ty::{self, CanonicalTy, TyCtxt, AdtDef, Ty, Region}; +use rustc::ty::{self, Region, TyCtxt, AdtDef, Ty}; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; @@ -69,7 +69,7 @@ pub enum PatternKind<'tcx> { Wild, AscribeUserType { - user_ty: CanonicalTy<'tcx>, + user_ty: UserTypeAnnotation<'tcx>, subpattern: Pattern<'tcx>, user_ty_span: Span, }, @@ -980,7 +980,7 @@ macro_rules! CloneImpls { CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, ast::NodeId, usize, &'tcx ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef, - &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, CanonicalTy<'tcx> + &'tcx Substs<'tcx>, &'tcx Kind<'tcx>, UserTypeAnnotation<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 48a2e67a3dc..46a957f453c 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -9,7 +9,8 @@ // except according to those terms. use rustc::hir; -use rustc::ty::{self, AdtDef, CanonicalTy, TyCtxt}; +use rustc::mir::UserTypeAnnotation; +use rustc::ty::{self, AdtDef, TyCtxt}; crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx>; @@ -20,32 +21,41 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { &self, hir_id: hir::HirId, adt_def: &'tcx AdtDef, - ) -> Option> { + ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; - Some(user_substs.unchecked_map(|user_substs| { - // Here, we just pair an `AdtDef` with the - // `user_substs`, so no new types etc are introduced. - self.tcx().mk_adt(adt_def, user_substs) - })) + Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( + |user_substs| { + // Here, we just pair an `AdtDef` with the + // `user_substs`, so no new types etc are introduced. + self.tcx().mk_adt(adt_def, user_substs) + }, + ))) } /// Looks up the type associated with this hir-id and applies the /// user-given substitutions; the hir-id must map to a suitable /// type. - fn user_substs_applied_to_ty_of_hir_id(&self, hir_id: hir::HirId) -> Option> { + fn user_substs_applied_to_ty_of_hir_id( + &self, + hir_id: hir::HirId, + ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; match &self.tables().node_id_to_type(hir_id).sty { - ty::Adt(adt_def, _) => Some(user_substs.unchecked_map(|user_substs| { - // Ok to call `unchecked_map` because we just pair an - // `AdtDef` with the `user_substs`, so no new types - // etc are introduced. - self.tcx().mk_adt(adt_def, user_substs) - })), - ty::FnDef(def_id, _) => Some(user_substs.unchecked_map(|user_substs| { - // Here, we just pair a `DefId` with the - // `user_substs`, so no new types etc are introduced. - self.tcx().mk_fn_def(*def_id, user_substs) - })), + ty::Adt(adt_def, _) => Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( + |user_substs| { + // Ok to call `unchecked_map` because we just pair an + // `AdtDef` with the `user_substs`, so no new types + // etc are introduced. + self.tcx().mk_adt(adt_def, user_substs) + }, + ))), + ty::FnDef(def_id, _) => Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( + |user_substs| { + // Here, we just pair a `DefId` with the + // `user_substs`, so no new types etc are introduced. + self.tcx().mk_fn_def(*def_id, user_substs) + }, + ))), sty => bug!( "sty: {:?} should not have user-substs {:?} recorded ", sty, From 2a7fc227a67a4d3abcc0f7a738c2fa419754840b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 10 Oct 2018 17:28:33 -0400 Subject: [PATCH 09/19] introduce `FnDef` and `AdtDef` to `UserTypeAnnotation` --- src/librustc/ich/impls_mir.rs | 8 ++++++ src/librustc/mir/mod.rs | 6 ++++- .../borrow_check/nll/type_check/relate_tys.rs | 16 ++++++++++-- src/librustc_mir/hair/cx/expr.rs | 17 ++----------- src/librustc_mir/hair/util.rs | 25 +++---------------- 5 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 38a298d81dd..b660187945c 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -597,6 +597,14 @@ impl<'a, 'gcx> HashStable> for mir::UserTypeAnnotation< mir::UserTypeAnnotation::Ty(ref ty) => { ty.hash_stable(hcx, hasher); } + mir::UserTypeAnnotation::FnDef(ref def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } + mir::UserTypeAnnotation::AdtDef(ref def_id, ref substs) => { + def_id.hash_stable(hcx, hasher); + substs.hash_stable(hcx, hasher); + } } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index eb4aa7ece49..278a9bba178 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -37,7 +37,7 @@ use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::subst::{Subst, Substs}; +use ty::subst::{CanonicalSubsts, Subst, Substs}; use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; use util::ppaux; @@ -2413,11 +2413,15 @@ pub struct Constant<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UserTypeAnnotation<'tcx> { Ty(CanonicalTy<'tcx>), + FnDef(DefId, CanonicalSubsts<'tcx>), + AdtDef(&'tcx AdtDef, CanonicalSubsts<'tcx>), } EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for UserTypeAnnotation<'tcx> { (UserTypeAnnotation::Ty)(ty), + (UserTypeAnnotation::FnDef)(def, substs), + (UserTypeAnnotation::AdtDef)(def, substs), } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 35d0b96b88a..21dabd0c1bd 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -71,9 +71,21 @@ pub(super) fn relate_type_and_user_type<'tcx>( a, v, user_ty, locations ); - let (b, _values) = match user_ty { + let b = match user_ty { UserTypeAnnotation::Ty(canonical_ty) => { - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty) + let (ty, _) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); + ty + } + UserTypeAnnotation::FnDef(def_id, canonical_substs) => { + let (substs, _) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + infcx.tcx.mk_fn_def(def_id, substs) + } + UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { + let (substs, _) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + infcx.tcx.mk_adt(adt_def, substs) } }; diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 4dc43a533cf..984abb03926 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -295,13 +295,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let substs = cx.tables().node_substs(fun.hir_id); let user_ty = cx.tables().user_substs(fun.hir_id) - .map(|user_substs| { - UserTypeAnnotation::Ty(user_substs.unchecked_map(|user_substs| { - // Here, we just pair an `AdtDef` with the - // `user_substs`, so no new types etc are introduced. - cx.tcx().mk_adt(adt_def, user_substs) - })) - }); + .map(|user_substs| UserTypeAnnotation::AdtDef(adt_def, user_substs)); let field_refs = args.iter() .enumerate() @@ -774,14 +768,7 @@ fn user_substs_applied_to_def( Def::Method(_) | Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => - Some( - UserTypeAnnotation::Ty(cx.tables().user_substs(hir_id)?.unchecked_map(|user_substs| { - // Here, we just pair a `DefId` with the - // `user_substs`, so no new types etc are introduced. - cx.tcx().mk_fn_def(def.def_id(), user_substs) - }), - ) - ), + Some(UserTypeAnnotation::FnDef(def.def_id(), cx.tables().user_substs(hir_id)?)), Def::Const(_def_id) | Def::AssociatedConst(_def_id) => diff --git a/src/librustc_mir/hair/util.rs b/src/librustc_mir/hair/util.rs index 46a957f453c..71cbac6b7c8 100644 --- a/src/librustc_mir/hair/util.rs +++ b/src/librustc_mir/hair/util.rs @@ -23,13 +23,7 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { adt_def: &'tcx AdtDef, ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; - Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( - |user_substs| { - // Here, we just pair an `AdtDef` with the - // `user_substs`, so no new types etc are introduced. - self.tcx().mk_adt(adt_def, user_substs) - }, - ))) + Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)) } /// Looks up the type associated with this hir-id and applies the @@ -41,21 +35,8 @@ crate trait UserAnnotatedTyHelpers<'gcx: 'tcx, 'tcx> { ) -> Option> { let user_substs = self.tables().user_substs(hir_id)?; match &self.tables().node_id_to_type(hir_id).sty { - ty::Adt(adt_def, _) => Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( - |user_substs| { - // Ok to call `unchecked_map` because we just pair an - // `AdtDef` with the `user_substs`, so no new types - // etc are introduced. - self.tcx().mk_adt(adt_def, user_substs) - }, - ))), - ty::FnDef(def_id, _) => Some(UserTypeAnnotation::Ty(user_substs.unchecked_map( - |user_substs| { - // Here, we just pair a `DefId` with the - // `user_substs`, so no new types etc are introduced. - self.tcx().mk_fn_def(*def_id, user_substs) - }, - ))), + ty::Adt(adt_def, _) => Some(UserTypeAnnotation::AdtDef(adt_def, user_substs)), + ty::FnDef(def_id, _) => Some(UserTypeAnnotation::FnDef(*def_id, user_substs)), sty => bug!( "sty: {:?} should not have user-substs {:?} recorded ", sty, From 1443ac0aa7d9c877b8fdbefbbd99092a517802d2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 17:18:51 -0400 Subject: [PATCH 10/19] introduce a more expressive `UserSubsts` --- src/librustc/ich/impls_ty.rs | 5 + src/librustc/mir/mod.rs | 6 +- src/librustc/ty/context.rs | 8 +- src/librustc/ty/subst.rs | 122 ++++++++++++++---- .../borrow_check/nll/type_check/relate_tys.rs | 7 +- src/librustc_typeck/check/mod.rs | 14 +- 6 files changed, 122 insertions(+), 40 deletions(-) diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index dd2c41dda64..e54968c5274 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1417,3 +1417,8 @@ impl_stable_hash_for!(enum traits::QuantifierKind { Universal, Existential }); + +impl_stable_hash_for!(struct ty::subst::UserSubsts<'tcx> { substs, user_self_ty }); + +impl_stable_hash_for!(struct ty::subst::UserSelfTy<'tcx> { impl_def_id, self_ty }); + diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 278a9bba178..48b2ccbcf87 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -37,7 +37,7 @@ use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::subst::{CanonicalSubsts, Subst, Substs}; +use ty::subst::{CanonicalUserSubsts, Subst, Substs}; use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; use util::ppaux; @@ -2413,8 +2413,8 @@ pub struct Constant<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum UserTypeAnnotation<'tcx> { Ty(CanonicalTy<'tcx>), - FnDef(DefId, CanonicalSubsts<'tcx>), - AdtDef(&'tcx AdtDef, CanonicalSubsts<'tcx>), + FnDef(DefId, CanonicalUserSubsts<'tcx>), + AdtDef(&'tcx AdtDef, CanonicalUserSubsts<'tcx>), } EnumTypeFoldableImpl! { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index ab1df2d4c3b..6f0f258a217 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -33,7 +33,7 @@ use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; use mir::interpret::Allocation; -use ty::subst::{CanonicalSubsts, Kind, Substs, Subst}; +use ty::subst::{CanonicalUserSubsts, Kind, Substs, Subst}; use ty::ReprOptions; use traits; use traits::{Clause, Clauses, GoalKind, Goal, Goals}; @@ -383,7 +383,7 @@ pub struct TypeckTables<'tcx> { /// If the user wrote `foo.collect::>()`, then the /// canonical substitutions would include only `for { Vec /// }`. - user_substs: ItemLocalMap>, + user_substs: ItemLocalMap>, adjustments: ItemLocalMap>>, @@ -573,14 +573,14 @@ impl<'tcx> TypeckTables<'tcx> { self.node_substs.get(&id.local_id).cloned() } - pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalSubsts<'tcx>> { + pub fn user_substs_mut(&mut self) -> LocalTableInContextMut<'_, CanonicalUserSubsts<'tcx>> { LocalTableInContextMut { local_id_root: self.local_id_root, data: &mut self.user_substs } } - pub fn user_substs(&self, id: hir::HirId) -> Option> { + pub fn user_substs(&self, id: hir::HirId) -> Option> { validate_hir_id_for_typeck_tables(self.local_id_root, id, false); self.user_substs.get(&id.local_id).cloned() } diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index c0a42fd5854..bea5ba04f7c 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -323,33 +323,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> { } } -pub type CanonicalSubsts<'gcx> = Canonical<'gcx, &'gcx Substs<'gcx>>; - -impl<'gcx> CanonicalSubsts<'gcx> { - /// True if this represents a substitution like - /// - /// ```text - /// [?0, ?1, ?2] - /// ``` - /// - /// i.e., each thing is mapped to a canonical variable with the same index. - pub fn is_identity(&self) -> bool { - self.value.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| { - match kind.unpack() { - UnpackedKind::Type(ty) => match ty.sty { - ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1, - _ => false, - }, - - UnpackedKind::Lifetime(r) => match r { - ty::ReCanonical(cvar1) => cvar == *cvar1, - _ => false, - }, - } - }) - } -} - impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {} /////////////////////////////////////////////////////////////////////////// @@ -564,3 +537,98 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } + +pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; + +impl CanonicalUserSubsts<'tcx> { + /// True if this represents a substitution like + /// + /// ```text + /// [?0, ?1, ?2] + /// ``` + /// + /// i.e., each thing is mapped to a canonical variable with the same index. + pub fn is_identity(&self) -> bool { + if self.value.user_self_ty.is_some() { + return false; + } + + self.value.substs.iter().zip(CanonicalVar::new(0)..).all(|(kind, cvar)| { + match kind.unpack() { + UnpackedKind::Type(ty) => match ty.sty { + ty::Infer(ty::CanonicalTy(cvar1)) => cvar == cvar1, + _ => false, + }, + + UnpackedKind::Lifetime(r) => match r { + ty::ReCanonical(cvar1) => cvar == *cvar1, + _ => false, + }, + } + }) + } +} + +/// Stores the user-given substs to reach some fully qualified path +/// (e.g., `::Item` or `::Item`). +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UserSubsts<'tcx> { + /// The substitutions for the item as given by the user. + pub substs: &'tcx Substs<'tcx>, + + /// The self-type, in the case of a `::Item` path (when applied + /// to an inherent impl). See `UserSubsts` below. + pub user_self_ty: Option>, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserSubsts<'tcx> { + substs, + user_self_ty, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserSubsts<'a> { + type Lifted = UserSubsts<'tcx>; + substs, + user_self_ty, + } +} + +/// Specifies the user-given self-type. In the case of a path that +/// refers to a member in an inherent impl, this self-type is +/// sometimes needed to constrain the type parameters on the impl. For +/// example, in this code: +/// +/// ``` +/// struct Foo { } +/// impl Foo { fn method() { } } +/// ``` +/// +/// when you then have a path like `>::method`, +/// this struct would carry the def-id of the impl along with the +/// self-type `Foo`. Then we can instantiate the parameters of +/// the impl (with the substs from `UserSubsts`) and apply those to +/// the self-type, giving `Foo`. Finally, we unify that with +/// the self-type here, which contains `?A` to be `&'static u32` +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +pub struct UserSelfTy<'tcx> { + pub impl_def_id: DefId, + pub self_ty: Ty<'tcx>, +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for UserSelfTy<'tcx> { + impl_def_id, + self_ty, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for UserSelfTy<'a> { + type Lifted = UserSelfTy<'tcx>; + impl_def_id, + self_ty, + } +} diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index 21dabd0c1bd..ebf9c7b4826 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -15,6 +15,7 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; use rustc::traits::query::Fallible; use rustc::ty::relate::TypeRelation; +use rustc::ty::subst::UserSubsts; use rustc::ty::{self, Ty}; use syntax_pos::DUMMY_SP; @@ -78,13 +79,15 @@ pub(super) fn relate_type_and_user_type<'tcx>( ty } UserTypeAnnotation::FnDef(def_id, canonical_substs) => { - let (substs, _) = + let (UserSubsts { substs, user_self_ty }, _) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + assert!(user_self_ty.is_none()); // TODO for now infcx.tcx.mk_fn_def(def_id, substs) } UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { - let (substs, _) = + let (UserSubsts { substs, user_self_ty }, _) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + assert!(user_self_ty.is_none()); // TODO for now infcx.tcx.mk_adt(adt_def, substs) } }; diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index be8b16dd2f5..62e4ef0f05c 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,7 @@ use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; -use rustc::ty::subst::{CanonicalSubsts, UnpackedKind, Subst, Substs}; +use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSubsts}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -2136,7 +2136,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { method.substs[i] } }); - self.infcx.canonicalize_response(&just_method_substs) + self.infcx.canonicalize_response(&UserSubsts { + substs: just_method_substs, + user_self_ty: None, // not relevant here + }) }); debug!("write_method_call: user_substs = {:?}", user_substs); @@ -2172,13 +2175,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ); if !substs.is_noop() { - let user_substs = self.infcx.canonicalize_response(&substs); + let user_substs = self.infcx.canonicalize_response(&UserSubsts { + substs, + user_self_ty: None, // TODO -- fix in future commit + }); debug!("instantiate_value_path: user_substs = {:?}", user_substs); self.write_user_substs(hir_id, user_substs); } } - pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalSubsts<'tcx>) { + pub fn write_user_substs(&self, hir_id: hir::HirId, substs: CanonicalUserSubsts<'tcx>) { debug!( "write_user_substs({:?}, {:?}) in fcx {}", hir_id, From 0e1d3624e990e84299ab75926c865f19353e9b2f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 17:43:05 -0400 Subject: [PATCH 11/19] pull the common code across user-ty variants up top --- .../borrow_check/nll/type_check/relate_tys.rs | 56 +++++++++++-------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index ebf9c7b4826..f59bcd53fa7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -72,26 +72,6 @@ pub(super) fn relate_type_and_user_type<'tcx>( a, v, user_ty, locations ); - let b = match user_ty { - UserTypeAnnotation::Ty(canonical_ty) => { - let (ty, _) = - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); - ty - } - UserTypeAnnotation::FnDef(def_id, canonical_substs) => { - let (UserSubsts { substs, user_self_ty }, _) = - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - assert!(user_self_ty.is_none()); // TODO for now - infcx.tcx.mk_fn_def(def_id, substs) - } - UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { - let (UserSubsts { substs, user_self_ty }, _) = - infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - assert!(user_self_ty.is_none()); // TODO for now - infcx.tcx.mk_adt(adt_def, substs) - } - }; - // The `TypeRelating` code assumes that the "canonical variables" // appear in the "a" side, so flip `Contravariant` ambient // variance to get the right relationship. @@ -102,9 +82,41 @@ pub(super) fn relate_type_and_user_type<'tcx>( NllTypeRelatingDelegate::new(infcx, borrowck_context, locations, category), v1, ); - type_relating.relate(&b, &a)?; - Ok(b) + match user_ty { + UserTypeAnnotation::Ty(canonical_ty) => { + let (ty, _) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_ty); + type_relating.relate(&ty, &a)?; + Ok(ty) + } + UserTypeAnnotation::FnDef(def_id, canonical_substs) => { + let ( + UserSubsts { + substs, + user_self_ty, + }, + _, + ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + assert!(user_self_ty.is_none()); // TODO for now + let ty = infcx.tcx.mk_fn_def(def_id, substs); + type_relating.relate(&ty, &a)?; + Ok(ty) + } + UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { + let ( + UserSubsts { + substs, + user_self_ty, + }, + _, + ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); + assert!(user_self_ty.is_none()); // TODO for now + let ty = infcx.tcx.mk_adt(adt_def, substs); + type_relating.relate(&ty, &a)?; + Ok(ty) + } + } } struct NllTypeRelatingDelegate<'me, 'bccx: 'me, 'gcx: 'tcx, 'tcx: 'bccx> { From 547182ea9463cdc4cf72f0af1372f4db17f700e8 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 18:06:30 -0400 Subject: [PATCH 12/19] handle user-self-type for def-ids --- .../borrow_check/nll/type_check/relate_tys.rs | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index f59bcd53fa7..a345d0484cf 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -15,7 +15,7 @@ use rustc::infer::{InferCtxt, NLLRegionVariableOrigin}; use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; use rustc::traits::query::Fallible; use rustc::ty::relate::TypeRelation; -use rustc::ty::subst::UserSubsts; +use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts}; use rustc::ty::{self, Ty}; use syntax_pos::DUMMY_SP; @@ -98,9 +98,24 @@ pub(super) fn relate_type_and_user_type<'tcx>( }, _, ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - assert!(user_self_ty.is_none()); // TODO for now let ty = infcx.tcx.mk_fn_def(def_id, substs); + type_relating.relate(&ty, &a)?; + + if let Some(UserSelfTy { + impl_def_id, + self_ty, + }) = user_self_ty + { + let impl_self_ty = infcx.tcx.type_of(impl_def_id); + let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs); + type_relating.relate_with_variance( + ty::Variance::Invariant, + &self_ty, + &impl_self_ty, + )?; + } + Ok(ty) } UserTypeAnnotation::AdtDef(adt_def, canonical_substs) => { @@ -111,7 +126,10 @@ pub(super) fn relate_type_and_user_type<'tcx>( }, _, ) = infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_substs); - assert!(user_self_ty.is_none()); // TODO for now + + // We don't extract adt-defs with a self-type. + assert!(user_self_ty.is_none()); + let ty = infcx.tcx.mk_adt(adt_def, substs); type_relating.relate(&ty, &a)?; Ok(ty) From 16a382407be00a1a7d3a9f9853378ecf69ff662c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 20:38:23 -0400 Subject: [PATCH 13/19] pass along `user_self_ty` --- src/librustc_typeck/check/mod.rs | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 62e4ef0f05c..c472aae4f6b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -95,7 +95,8 @@ use rustc::infer::opaque_types::OpaqueTypeDecl; use rustc::infer::type_variable::{TypeVariableOrigin}; use rustc::middle::region; use rustc::mir::interpret::{ConstValue, GlobalId}; -use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, UserSubsts}; +use rustc::ty::subst::{CanonicalUserSubsts, UnpackedKind, Subst, Substs, + UserSelfTy, UserSubsts}; use rustc::traits::{self, ObligationCause, ObligationCauseCode, TraitEngine}; use rustc::ty::{self, Ty, TyCtxt, GenericParamDefKind, Visibility, ToPredicate, RegionKind}; use rustc::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability}; @@ -2166,7 +2167,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { /// This should be invoked **before any unifications have /// occurred**, so that annotations like `Vec<_>` are preserved /// properly. - pub fn write_user_substs_from_substs(&self, hir_id: hir::HirId, substs: &'tcx Substs<'tcx>) { + pub fn write_user_substs_from_substs( + &self, + hir_id: hir::HirId, + substs: &'tcx Substs<'tcx>, + user_self_ty: Option>, + ) { debug!( "write_user_substs_from_substs({:?}, {:?}) in fcx {}", hir_id, @@ -2177,7 +2183,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if !substs.is_noop() { let user_substs = self.infcx.canonicalize_response(&UserSubsts { substs, - user_self_ty: None, // TODO -- fix in future commit + user_self_ty, }); debug!("instantiate_value_path: user_substs = {:?}", user_substs); self.write_user_substs(hir_id, user_substs); @@ -3623,7 +3629,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { if let Some((variant, did, substs)) = variant { debug!("check_struct_path: did={:?} substs={:?}", did, substs); let hir_id = self.tcx.hir.node_to_hir_id(node_id); - self.write_user_substs_from_substs(hir_id, substs); + self.write_user_substs_from_substs(hir_id, substs, None); // Check bounds on type arguments used in the path. let bounds = self.instantiate_bounds(path_span, did, substs); @@ -5011,7 +5017,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let path_segs = self.def_ids_for_path_segments(segments, def); - let mut ufcs_associated = None; + let mut user_self_ty = None; match def { Def::Method(def_id) | Def::AssociatedConst(def_id) => { @@ -5020,12 +5026,20 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty::TraitContainer(trait_did) => { callee::check_legal_trait_for_method_call(self.tcx, span, trait_did) } - ty::ImplContainer(_) => {} - } - if segments.len() == 1 { - // `::assoc` will end up here, and so can `T::assoc`. - let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); - ufcs_associated = Some((container, self_ty)); + ty::ImplContainer(impl_def_id) => { + if segments.len() == 1 { + // `::assoc` will end up here, and so + // can `T::assoc`. It this came from an + // inherent impl, we need to record the + // `T` for posterity (see `UserSelfTy` for + // details). + let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); + user_self_ty = Some(UserSelfTy { + impl_def_id, + self_ty, + }); + } + } } } _ => {} @@ -5179,6 +5193,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { assert!(!substs.has_escaping_regions()); assert!(!ty.has_escaping_regions()); + // Write the "user substs" down first thing for later. + let hir_id = self.tcx.hir.node_to_hir_id(node_id); + self.write_user_substs_from_substs(hir_id, substs, user_self_ty); + // Add all the obligations that are required, substituting and // normalized appropriately. let bounds = self.instantiate_bounds(span, def_id, &substs); @@ -5190,7 +5208,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // the referenced item. let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); - if let Some((ty::ImplContainer(impl_def_id), self_ty)) = ufcs_associated { + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { // In the case of `Foo::method` and `>::method`, if `method` // is inherent, there is no `Self` parameter, instead, the impl needs // type parameters, which we can infer by unifying the provided `Self` @@ -5214,16 +5232,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { debug!("instantiate_value_path: type of {:?} is {:?}", node_id, ty_substituted); - let hir_id = self.tcx.hir.node_to_hir_id(node_id); self.write_substs(hir_id, substs); - debug!( - "instantiate_value_path: id={:?} substs={:?}", - node_id, - substs, - ); - self.write_user_substs_from_substs(hir_id, substs); - (ty_substituted, new_def) } From ba20806e469958a935a320b2a6c82f4971387c3b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 11 Oct 2018 18:23:23 -0400 Subject: [PATCH 14/19] avoid type variables in the self-type --- .../borrow_check/nll/type_check/relate_tys.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index a345d0484cf..72120eb1841 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -16,7 +16,7 @@ use rustc::mir::{ConstraintCategory, UserTypeAnnotation}; use rustc::traits::query::Fallible; use rustc::ty::relate::TypeRelation; use rustc::ty::subst::{Subst, UserSelfTy, UserSubsts}; -use rustc::ty::{self, Ty}; +use rustc::ty::{self, Ty, TypeFoldable}; use syntax_pos::DUMMY_SP; /// Adds sufficient constraints to ensure that `a <: b`. @@ -109,6 +109,18 @@ pub(super) fn relate_type_and_user_type<'tcx>( { let impl_self_ty = infcx.tcx.type_of(impl_def_id); let impl_self_ty = impl_self_ty.subst(infcx.tcx, &substs); + + // 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 = infcx.resolve_type_vars_if_possible(&impl_self_ty); + assert!(!impl_self_ty.has_infer_types()); + type_relating.relate_with_variance( ty::Variance::Invariant, &self_ty, From 2e4e98335662dd0636338a0dfbbaf234f7ed473b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 06:14:08 -0400 Subject: [PATCH 15/19] update tests --- .../dump-adt-brace-struct.stderr | 2 +- .../user-annotations/dump-fn-method.stderr | 8 ++--- .../method-ufcs-inherent-1.rs | 19 ++++++++++++ .../method-ufcs-inherent-1.stderr | 17 ++++++++++ .../method-ufcs-inherent-2.rs | 19 ++++++++++++ .../method-ufcs-inherent-2.stderr | 31 +++++++++++++++++++ .../method-ufcs-inherent-3.rs | 19 ++++++++++++ .../method-ufcs-inherent-3.stderr | 17 ++++++++++ .../method-ufcs-inherent-4.rs | 20 ++++++++++++ .../method-ufcs-inherent-4.stderr | 31 +++++++++++++++++++ 10 files changed, 178 insertions(+), 5 deletions(-) create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs create mode 100644 src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr diff --git a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr index 2b0e5039d8d..901ace59d33 100644 --- a/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr +++ b/src/test/ui/nll/user-annotations/dump-adt-brace-struct.stderr @@ -1,4 +1,4 @@ -error: user substs: Canonical { variables: [], value: [u32] } +error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } } --> $DIR/dump-adt-brace-struct.rs:28:5 | LL | SomeStruct:: { t: 22 }; //~ ERROR [u32] diff --git a/src/test/ui/nll/user-annotations/dump-fn-method.stderr b/src/test/ui/nll/user-annotations/dump-fn-method.stderr index 6531f87dd98..a26be359fc4 100644 --- a/src/test/ui/nll/user-annotations/dump-fn-method.stderr +++ b/src/test/ui/nll/user-annotations/dump-fn-method.stderr @@ -1,22 +1,22 @@ -error: user substs: Canonical { variables: [], value: [u32] } +error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u32], user_self_ty: None } } --> $DIR/dump-fn-method.rs:36:13 | LL | let x = foo::; //~ ERROR [u32] | ^^^^^^^^^^ -error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, u32, ?1] } +error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, u32, ?1], user_self_ty: None } } --> $DIR/dump-fn-method.rs:42:13 | LL | let x = <_ as Bazoom>::method::<_>; //~ ERROR [?0, u32, ?1] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { variables: [], value: [u8, u16, u32] } +error: user substs: Canonical { variables: [], value: UserSubsts { substs: [u8, u16, u32], user_self_ty: None } } --> $DIR/dump-fn-method.rs:46:13 | LL | let x = >::method::; //~ ERROR [u8, u16, u32] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: [?0, ?1, u32] } +error: user substs: Canonical { variables: [CanonicalVarInfo { kind: Ty(General) }, CanonicalVarInfo { kind: Ty(General) }], value: UserSubsts { substs: [?0, ?1, u32], user_self_ty: None } } --> $DIR/dump-fn-method.rs:54:5 | LL | y.method::(44, 66); //~ ERROR [?0, ?1, u32] diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs new file mode 100644 index 00000000000..4bca114e953 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs @@ -0,0 +1,19 @@ +#![feature(nll)] + +// Check that substitutions given on the self type (here, `A`) carry +// through to NLL. + +struct A<'a> { x: &'a u32 } + +impl<'a> A<'a> { + fn new<'b, T>(x: &'a u32, y: T) -> Self { + Self { x } + } +} + +fn foo<'a>() { + let v = 22; + let x = A::<'a>::new(&v, 22); +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr new file mode 100644 index 00000000000..68a7684c963 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr @@ -0,0 +1,17 @@ +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-1.rs:16:26 + | +LL | let x = A::<'a>::new(&v, 22); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8... + --> $DIR/method-ufcs-inherent-1.rs:14:8 + | +LL | fn foo<'a>() { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs new file mode 100644 index 00000000000..f87f5cba391 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs @@ -0,0 +1,19 @@ +#![feature(nll)] + +// Check that substitutions given on the self type (here, `A`) can be +// used in combination with annotations given for method arguments. + +struct A<'a> { x: &'a u32 } + +impl<'a> A<'a> { + fn new<'b, T>(x: &'a u32, y: T) -> Self { + Self { x } + } +} + +fn foo<'a>() { + let v = 22; + let x = A::<'a>::new::<&'a u32>(&v, &v); +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr new file mode 100644 index 00000000000..0bdff99da9e --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr @@ -0,0 +1,31 @@ +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-2.rs:16:37 + | +LL | let x = A::<'a>::new::<&'a u32>(&v, &v); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8... + --> $DIR/method-ufcs-inherent-2.rs:14:8 + | +LL | fn foo<'a>() { + | ^^ + +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-2.rs:16:41 + | +LL | let x = A::<'a>::new::<&'a u32>(&v, &v); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8... + --> $DIR/method-ufcs-inherent-2.rs:14:8 + | +LL | fn foo<'a>() { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs new file mode 100644 index 00000000000..d8376e4bdc4 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs @@ -0,0 +1,19 @@ +#![feature(nll)] + +// Check that inherent methods invoked with `::new` style +// carry their annotations through to NLL. + +struct A<'a> { x: &'a u32 } + +impl<'a> A<'a> { + fn new<'b, T>(x: &'a u32, y: T) -> Self { + Self { x } + } +} + +fn foo<'a>() { + let v = 22; + let x = >::new(&v, 22); +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr new file mode 100644 index 00000000000..122b26c72b2 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr @@ -0,0 +1,17 @@ +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-3.rs:16:26 + | +LL | let x = >::new(&v, 22); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 14:8... + --> $DIR/method-ufcs-inherent-3.rs:14:8 + | +LL | fn foo<'a>() { + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs new file mode 100644 index 00000000000..e0fb9cedd37 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs @@ -0,0 +1,20 @@ +#![feature(nll)] + +// Check that inherent methods invoked with `::new` style +// carry their annotations through to NLL in connection with +// method type parameters. + +struct A<'a> { x: &'a u32 } + +impl<'a> A<'a> { + fn new<'b, T>(x: &'a u32, y: T) -> Self { + Self { x } + } +} + +fn foo<'a>() { + let v = 22; + let x = >::new::<&'a u32>(&v, &v); +} + +fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr new file mode 100644 index 00000000000..b2f4066b2e8 --- /dev/null +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr @@ -0,0 +1,31 @@ +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-4.rs:17:37 + | +LL | let x = >::new::<&'a u32>(&v, &v); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8... + --> $DIR/method-ufcs-inherent-4.rs:15:8 + | +LL | fn foo<'a>() { + | ^^ + +error[E0597]: `v` does not live long enough + --> $DIR/method-ufcs-inherent-4.rs:17:41 + | +LL | let x = >::new::<&'a u32>(&v, &v); + | ^^ borrowed value does not live long enough +LL | } + | - `v` dropped here while still borrowed + | +note: borrowed value must be valid for the lifetime 'a as defined on the function body at 15:8... + --> $DIR/method-ufcs-inherent-4.rs:15:8 + | +LL | fn foo<'a>() { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0597`. From 087d12972e822f4ee13223ece76443e7018e705b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 09:31:38 -0400 Subject: [PATCH 16/19] pacify the mercilous tidy (long lines) --- src/librustc/mir/visit.rs | 10 ++++++++-- src/librustc_mir/hair/cx/expr.rs | 6 +++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 3e92b1fd7ce..76c76404d2f 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -214,7 +214,10 @@ macro_rules! make_mir_visitor { self.super_ty(ty); } - fn visit_user_type_annotation(&mut self, ty: & $($mutability)* UserTypeAnnotation<'tcx>) { + fn visit_user_type_annotation( + &mut self, + ty: & $($mutability)* UserTypeAnnotation<'tcx>, + ) { self.super_user_type_annotation(ty); } @@ -783,7 +786,10 @@ macro_rules! make_mir_visitor { self.visit_source_scope(scope); } - fn super_user_type_annotation(&mut self, _ty: & $($mutability)* UserTypeAnnotation<'tcx>) { + fn super_user_type_annotation( + &mut self, + _ty: & $($mutability)* UserTypeAnnotation<'tcx>, + ) { } fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 984abb03926..56a29f29d68 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -722,7 +722,11 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let user_ty = UserTypeAnnotation::Ty( *user_provided_tys .get(ty.hir_id) - .expect(&format!("{:?} not found in user_provided_tys, source: {:?}", ty, source)) + .expect(&format!( + "{:?} not found in user_provided_tys, source: {:?}", + ty, + source, + )) ); if source.is_place_expr() { ExprKind::PlaceTypeAscription { From 7ce2e7a5faad9bb7fd2b49072c8d1399dc801933 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Oct 2018 12:27:01 -0400 Subject: [PATCH 17/19] fix mir-opt test --- src/test/mir-opt/basic_assignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/mir-opt/basic_assignment.rs b/src/test/mir-opt/basic_assignment.rs index 1abe63afa80..64e574fa8ae 100644 --- a/src/test/mir-opt/basic_assignment.rs +++ b/src/test/mir-opt/basic_assignment.rs @@ -56,7 +56,7 @@ fn main() { // StorageLive(_4); // _4 = std::option::Option>::None; // FakeRead(ForLet, _4); -// AscribeUserType(_4, o, Canonical { variables: [], value: std::option::Option> }); +// AscribeUserType(_4, o, Ty(Canonical { variables: [], value: std::option::Option> })); // StorageLive(_5); // StorageLive(_6); // _6 = move _4; From 1008539ca6a45043261854ce5ccf52df04b10c01 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Oct 2018 17:58:32 -0400 Subject: [PATCH 18/19] fix comment --- src/librustc/ty/subst.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index bea5ba04f7c..64cfba7df6e 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -577,7 +577,7 @@ pub struct UserSubsts<'tcx> { pub substs: &'tcx Substs<'tcx>, /// The self-type, in the case of a `::Item` path (when applied - /// to an inherent impl). See `UserSubsts` below. + /// to an inherent impl). See `UserSelfTy` below. pub user_self_ty: Option>, } From b70b4a6814d420222f28684f9286a21ddb980bcf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 16 Oct 2018 18:11:55 -0400 Subject: [PATCH 19/19] add ~ERROR annotations --- src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs | 1 + src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr | 1 + src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs | 2 ++ src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr | 2 ++ src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs | 1 + src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr | 1 + src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs | 2 ++ src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr | 2 ++ 8 files changed, 12 insertions(+) diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs index 4bca114e953..b7292c0acbe 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.rs @@ -14,6 +14,7 @@ impl<'a> A<'a> { fn foo<'a>() { let v = 22; let x = A::<'a>::new(&v, 22); + //~^ ERROR } fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr index 68a7684c963..aa133ce286d 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-1.stderr @@ -3,6 +3,7 @@ error[E0597]: `v` does not live long enough | LL | let x = A::<'a>::new(&v, 22); | ^^ borrowed value does not live long enough +LL | //~^ ERROR LL | } | - `v` dropped here while still borrowed | diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs index f87f5cba391..a77d6af5323 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.rs @@ -14,6 +14,8 @@ impl<'a> A<'a> { fn foo<'a>() { let v = 22; let x = A::<'a>::new::<&'a u32>(&v, &v); + //~^ ERROR + //~| ERROR } fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr index 0bdff99da9e..f1f4787d058 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-2.stderr @@ -3,6 +3,7 @@ error[E0597]: `v` does not live long enough | LL | let x = A::<'a>::new::<&'a u32>(&v, &v); | ^^ borrowed value does not live long enough +... LL | } | - `v` dropped here while still borrowed | @@ -17,6 +18,7 @@ error[E0597]: `v` does not live long enough | LL | let x = A::<'a>::new::<&'a u32>(&v, &v); | ^^ borrowed value does not live long enough +... LL | } | - `v` dropped here while still borrowed | diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs index d8376e4bdc4..24d83c468f4 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.rs @@ -14,6 +14,7 @@ impl<'a> A<'a> { fn foo<'a>() { let v = 22; let x = >::new(&v, 22); + //~^ ERROR } fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr index 122b26c72b2..f3766a8c8e5 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-3.stderr @@ -3,6 +3,7 @@ error[E0597]: `v` does not live long enough | LL | let x = >::new(&v, 22); | ^^ borrowed value does not live long enough +LL | //~^ ERROR LL | } | - `v` dropped here while still borrowed | diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs index e0fb9cedd37..3f88c3df48e 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.rs @@ -15,6 +15,8 @@ impl<'a> A<'a> { fn foo<'a>() { let v = 22; let x = >::new::<&'a u32>(&v, &v); + //~^ ERROR + //~| ERROR } fn main() {} diff --git a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr index b2f4066b2e8..c9bce5077d6 100644 --- a/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr +++ b/src/test/ui/nll/user-annotations/method-ufcs-inherent-4.stderr @@ -3,6 +3,7 @@ error[E0597]: `v` does not live long enough | LL | let x = >::new::<&'a u32>(&v, &v); | ^^ borrowed value does not live long enough +... LL | } | - `v` dropped here while still borrowed | @@ -17,6 +18,7 @@ error[E0597]: `v` does not live long enough | LL | let x = >::new::<&'a u32>(&v, &v); | ^^ borrowed value does not live long enough +... LL | } | - `v` dropped here while still borrowed |