diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index a73fe2b8a1ab3..910427da044d4 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -453,6 +453,7 @@ impl_stable_hash_for!(enum mir::CastKind { ReifyFnPointer, ClosureFnPointer, UnsafeFnPointer, + Hide, Unsize }); diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 7d25ecedb4e04..30bc242524ef2 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -183,6 +183,7 @@ for ty::adjustment::Adjust<'gcx> { ty::adjustment::Adjust::UnsafeFnPointer | ty::adjustment::Adjust::ClosureFnPointer | ty::adjustment::Adjust::MutToConstPointer | + ty::adjustment::Adjust::Hide | ty::adjustment::Adjust::Unsize => {} ty::adjustment::Adjust::Deref(ref overloaded) => { overloaded.hash_stable(hcx, hasher); diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index f5513acecf9e7..a5db5fe95f0a8 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -1057,7 +1057,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { Substs::for_item(self.tcx, def_id, |param, _| self.var_for_def(span, param)) } - /// True if errors have been reported since this infcx was + /// Returns `true` if errors have been reported since this infcx was /// created. This is sometimes used as a heuristic to skip /// reporting errors that often occur as a result of earlier /// errors, but where it's hard to be 100% sure (e.g., unresolved @@ -1251,7 +1251,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { value.fold_with(&mut r) } - /// Returns true if `T` contains unresolved type variables. In the + /// Returns `true` if `T` contains unresolved type variables. In the /// process of visiting `T`, this will resolve (where possible) /// type variables in `T`, but it never constructs the final, /// resolved type, so it's more efficient than diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 7e9b26bbf729c..7a3f1974f2110 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -721,6 +721,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { adjustment::Adjust::UnsafeFnPointer | adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | + adjustment::Adjust::Hide | adjustment::Adjust::Unsize => { // Creating a closure/fn-pointer or unsizing consumes // the input and stores it into the resulting rvalue. diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 9d3f37bc36a9d..2df048c70a2a3 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -631,6 +631,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::ClosureFnPointer | adjustment::Adjust::MutToConstPointer | adjustment::Adjust::Borrow(_) | + adjustment::Adjust::Hide | adjustment::Adjust::Unsize => { // Result is an rvalue. Ok(self.cat_rvalue_node(expr.hir_id, expr.span, target)) diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index c2014a5fdd23a..e6081ff5d5f9c 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2128,16 +2128,16 @@ impl<'tcx> Operand<'tcx> { #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum Rvalue<'tcx> { - /// x (either a move or copy, depending on type of x) + /// `x` (either a move or copy, depending on type of `x`) Use(Operand<'tcx>), - /// [x; 32] + /// `[x; 32]` Repeat(Operand<'tcx>, u64), - /// &x or &mut x + /// `&x` or `&mut x` Ref(Region<'tcx>, BorrowKind, Place<'tcx>), - /// length of a [X] or [X;n] value + /// length of a `[X]` or `[X;n]` value Len(Place<'tcx>), Cast(CastKind, Operand<'tcx>, Ty<'tcx>), @@ -2166,15 +2166,19 @@ pub enum Rvalue<'tcx> { pub enum CastKind { Misc, - /// Convert unique, zero-sized type for a fn to fn() + /// Convert a unique, zero-sized type for a fn to `fn()` ReifyFnPointer, - /// Convert non capturing closure to fn() + /// Convert a non capturing closure to `fn()` ClosureFnPointer, - /// Convert safe fn() to unsafe fn() + /// Convert a safe fn() to unsafe `fn()` UnsafeFnPointer, + // "Hide" -- convert a value to an opaque type, i.e. `impl Trait`, + // thus hiding information about its conrete type. + Hide, + /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. /// codegen must figure out the details once full monomorphization /// is known. For example, this could be used to cast from a @@ -2185,7 +2189,7 @@ pub enum CastKind { #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum AggregateKind<'tcx> { - /// The type is of the element + /// The type is of the element. Array(Ty<'tcx>), Tuple, diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index b7512790bfb69..8b3e364a4d4a2 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -94,7 +94,7 @@ pub enum TraitQueryMode { Canonical, } -/// An `Obligation` represents some trait reference (e.g. `int:Eq`) for +/// An `Obligation` represents some trait reference (e.g. `int: Eq`) for /// which the vtable must be found. The process of finding a vtable is /// called "resolving" the `Obligation`. This process consists of /// either identifying an `impl` (e.g., `impl Eq for int`) that @@ -1015,7 +1015,7 @@ fn vtable_methods<'a, 'tcx>( ) } -impl<'tcx,O> Obligation<'tcx,O> { +impl<'tcx, O> Obligation<'tcx, O> { pub fn new(cause: ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, predicate: O) diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 74f8d67ce0484..27ed7829349b2 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -393,7 +393,7 @@ pub fn impl_trait_ref_and_oblig<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, (impl_trait_ref, impl_obligations) } -/// See `super::obligations_for_generics` +/// See `super::predicates_for_generics`. pub fn predicates_for_generics<'tcx>(cause: ObligationCause<'tcx>, recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index 3263da8fda365..98ac4035d64b7 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -13,7 +13,6 @@ use hir::def_id::DefId; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; - /// Represents coercing a value to a different type of value. /// /// We transform values by following a number of `Adjust` steps in order. @@ -83,6 +82,9 @@ pub enum Adjust<'tcx> { /// Take the address and produce either a `&` or `*` pointer. Borrow(AutoBorrow<'tcx>), + /// Hide a value with an opaque type. + Hide, + /// Unsize a pointer/reference value, e.g. `&[T; n]` to /// `&[T]`. Note that the source could be a thin or fat pointer. /// This will do things like convert thin pointers to fat diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c7c197d11c03b..36334dd6ce544 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -993,6 +993,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { self.instantiate_into(tcx, &mut instantiated, substs); instantiated } + pub fn instantiate_own(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, substs: &Substs<'tcx>) -> InstantiatedPredicates<'tcx> { InstantiatedPredicates { @@ -1028,8 +1029,7 @@ impl<'a, 'gcx, 'tcx> GenericPredicates<'tcx> { pub fn instantiate_supertrait(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, poly_trait_ref: &ty::PolyTraitRef<'tcx>) - -> InstantiatedPredicates<'tcx> - { + -> InstantiatedPredicates<'tcx> { assert_eq!(self.parent, None); InstantiatedPredicates { predicates: self.predicates.iter().map(|(pred, _)| { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 59a66513eef05..36be45a562409 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -346,6 +346,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { Some(ty::adjustment::Adjust::ClosureFnPointer), ty::adjustment::Adjust::MutToConstPointer => Some(ty::adjustment::Adjust::MutToConstPointer), + ty::adjustment::Adjust::Hide => + Some(ty::adjustment::Adjust::Hide), ty::adjustment::Adjust::Unsize => Some(ty::adjustment::Adjust::Unsize), ty::adjustment::Adjust::Deref(ref overloaded) => { @@ -881,6 +883,7 @@ EnumTypeFoldableImpl! { (ty::adjustment::Adjust::UnsafeFnPointer), (ty::adjustment::Adjust::ClosureFnPointer), (ty::adjustment::Adjust::MutToConstPointer), + (ty::adjustment::Adjust::Hide), (ty::adjustment::Adjust::Unsize), (ty::adjustment::Adjust::Deref)(a), (ty::adjustment::Adjust::Borrow)(a), diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 28b58d62175bc..2f53ee8781ae4 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -190,8 +190,8 @@ pub enum TyKind<'tcx> { /// Opaque (`impl Trait`) type found in a return type. /// The `DefId` comes either from - /// * the `impl Trait` ast::Ty node, - /// * or the `existential type` declaration + /// * the `impl Trait` `ast::Ty` node, + /// * the `existential type` declaration. /// The substitutions are for the generics of the function in question. /// After typeck, the concrete type can be found in the `types` map. Opaque(DefId, &'tcx Substs<'tcx>), @@ -582,7 +582,7 @@ impl<'tcx> List> { #[inline] pub fn projection_bounds<'a>(&'a self) -> - impl Iterator> + 'a { + impl Iterator> + 'a { self.iter().filter_map(|predicate| { match *predicate { ExistentialPredicate::Projection(p) => Some(p), @@ -592,7 +592,7 @@ impl<'tcx> List> { } #[inline] - pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { + pub fn auto_traits<'a>(&'a self) -> impl Iterator + 'a { self.iter().filter_map(|predicate| { match *predicate { ExistentialPredicate::AutoTrait(d) => Some(d), @@ -619,7 +619,7 @@ impl<'tcx> Binder<&'tcx List>> { } pub fn iter<'a>(&'a self) - -> impl DoubleEndedIterator>> + 'tcx { + -> impl DoubleEndedIterator>> + 'tcx { self.skip_binder().iter().cloned().map(Binder::bind) } } diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index d1b6aa7fc4280..b090632c56d9a 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -334,9 +334,9 @@ impl OperandValue<'ll> { impl FunctionCx<'a, 'll, 'tcx> { fn maybe_codegen_consume_direct(&mut self, - bx: &Builder<'a, 'll, 'tcx>, - place: &mir::Place<'tcx>) - -> Option> + bx: &Builder<'a, 'll, 'tcx>, + place: &mir::Place<'tcx>) + -> Option> { debug!("maybe_codegen_consume_direct(place={:?})", place); @@ -382,9 +382,9 @@ impl FunctionCx<'a, 'll, 'tcx> { } pub fn codegen_consume(&mut self, - bx: &Builder<'a, 'll, 'tcx>, - place: &mir::Place<'tcx>) - -> OperandRef<'ll, 'tcx> + bx: &Builder<'a, 'll, 'tcx>, + place: &mir::Place<'tcx>) + -> OperandRef<'ll, 'tcx> { debug!("codegen_consume(place={:?})", place); @@ -406,9 +406,9 @@ impl FunctionCx<'a, 'll, 'tcx> { } pub fn codegen_operand(&mut self, - bx: &Builder<'a, 'll, 'tcx>, - operand: &mir::Operand<'tcx>) - -> OperandRef<'ll, 'tcx> + bx: &Builder<'a, 'll, 'tcx>, + operand: &mir::Operand<'tcx>) + -> OperandRef<'ll, 'tcx> { debug!("codegen_operand(operand={:?})", operand); diff --git a/src/librustc_codegen_llvm/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs index fa22bdff94ddd..dd62e6c56ae8b 100644 --- a/src/librustc_codegen_llvm/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -34,10 +34,10 @@ use super::place::PlaceRef; impl FunctionCx<'a, 'll, 'tcx> { pub fn codegen_rvalue(&mut self, - bx: Builder<'a, 'll, 'tcx>, - dest: PlaceRef<'ll, 'tcx>, - rvalue: &mir::Rvalue<'tcx>) - -> Builder<'a, 'll, 'tcx> + bx: Builder<'a, 'll, 'tcx>, + dest: PlaceRef<'ll, 'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> Builder<'a, 'll, 'tcx> { debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})", dest.llval, rvalue); @@ -199,9 +199,9 @@ impl FunctionCx<'a, 'll, 'tcx> { } pub fn codegen_rvalue_operand(&mut self, - bx: Builder<'a, 'll, 'tcx>, - rvalue: &mir::Rvalue<'tcx>) - -> (Builder<'a, 'll, 'tcx>, OperandRef<'ll, 'tcx>) + bx: Builder<'a, 'll, 'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> (Builder<'a, 'll, 'tcx>, OperandRef<'ll, 'tcx>) { assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {:?} to operand", rvalue); @@ -240,9 +240,12 @@ impl FunctionCx<'a, 'll, 'tcx> { } } mir::CastKind::UnsafeFnPointer => { - // this is a no-op at the LLVM level + // This is a no-op at the LLVM level. operand.val } + mir::CastKind::Hide => { + return (bx, operand); + } mir::CastKind::Unsize => { assert!(cast.is_llvm_scalar_pair()); match operand.val { @@ -442,6 +445,7 @@ impl FunctionCx<'a, 'll, 'tcx> { }; (bx, operand) } + mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { let lhs = self.codegen_operand(&bx, lhs); let rhs = self.codegen_operand(&bx, rhs); @@ -521,10 +525,12 @@ impl FunctionCx<'a, 'll, 'tcx> { }; (bx, operand) } + mir::Rvalue::Use(ref operand) => { let operand = self.codegen_operand(&bx, operand); (bx, operand) } + mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => { // According to `rvalue_creates_operand`, only ZST 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 734ddbc3ab9a7..d1ec07b4ccbc0 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -973,6 +973,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { + // FIXME(alexreg): see issue #54600. if let Err(terr) = self.sub_types(sub, sup, locations, category) { if let TyKind::Opaque(..) = sup.sty { // When you have `let x: impl Foo = ...` in a closure, @@ -1059,17 +1060,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { fn eq_opaque_type_and_type( &mut self, - revealed_ty: Ty<'tcx>, - anon_ty: Ty<'tcx>, - anon_owner_def_id: DefId, + concrete_ty: Ty<'tcx>, + opaque_ty: Ty<'tcx>, + parent_def_id: DefId, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { debug!( "eq_opaque_type_and_type( \ - revealed_ty={:?}, \ - anon_ty={:?})", - revealed_ty, anon_ty + concrete_ty={:?}, \ + opaque_ty={:?})", + concrete_ty, opaque_ty ); let infcx = self.infcx; let tcx = infcx.tcx; @@ -1085,21 +1086,21 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let dummy_body_id = ObligationCause::dummy().body_id; let (output_ty, opaque_type_map) = obligations.add(infcx.instantiate_opaque_types( - anon_owner_def_id, + parent_def_id, dummy_body_id, param_env, - &anon_ty, + &opaque_ty, )); debug!( "eq_opaque_type_and_type: \ instantiated output_ty={:?} \ opaque_type_map={:#?} \ - revealed_ty={:?}", - output_ty, opaque_type_map, revealed_ty + concrete_ty={:?}", + output_ty, opaque_type_map, concrete_ty ); obligations.add(infcx .at(&ObligationCause::dummy(), param_env) - .eq(output_ty, revealed_ty)?); + .eq(output_ty, concrete_ty)?); for (&opaque_def_id, opaque_decl) in &opaque_type_map { let opaque_defn_ty = tcx.type_of(opaque_def_id); @@ -1524,7 +1525,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } None => { - // FIXME(canndrew): This is_never should probably be an is_uninhabited + // FIXME(canndrew): this `is_never` should probably be an `is_uninhabited`. if !sig.output().is_never() { span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig); } @@ -1910,6 +1911,25 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } + CastKind::Hide => { + let predicates = match ty.sty { + ty::Opaque(def_id, substs) => { + let bounds = tcx.predicates_of(def_id); + let result = bounds.instantiate(tcx, substs); + // TODO: do I need to normalize associated types here somehow. + // as is done in coercion.rs? + result + } + _ => bug!(), + }; + + self.prove_predicates( + predicates.predicates, + location.to_locations(), + ConstraintCategory::Cast, + ); + } + CastKind::Unsize => { let &ty = ty; let trait_ref = ty::TraitRef { @@ -1932,7 +1952,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { self.add_reborrow_constraint(location, region, borrowed_place); } - // FIXME: These other cases have to be implemented in future PRs + // FIXME: these other cases have to be implemented in future PRs. Rvalue::Use(..) | Rvalue::Len(..) | Rvalue::BinaryOp(..) @@ -2164,7 +2184,6 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } // For closures, we have some **extra requirements** we - // // have to check. In particular, in their upvars and // signatures, closures often reference various regions // from the surrounding function -- we call those the diff --git a/src/librustc_mir/build/expr/as_place.rs b/src/librustc_mir/build/expr/as_place.rs index 77746e5538d65..e7938b00f5fe9 100644 --- a/src/librustc_mir/build/expr/as_place.rs +++ b/src/librustc_mir/build/expr/as_place.rs @@ -189,6 +189,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::ReifyFnPointer { .. } | ExprKind::ClosureFnPointer { .. } | ExprKind::UnsafeFnPointer { .. } + | ExprKind::Hide { .. } | ExprKind::Unsize { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } @@ -205,7 +206,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::InlineAsm { .. } | ExprKind::Yield { .. } | ExprKind::Call { .. } => { - // these are not places, so we need to make a temporary. + // These are not places, so we need to make a temporary. debug_assert!(match Category::of(&expr.kind) { Some(Category::Place) => false, _ => true, diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 8fee74390cc6b..749203765abb6 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -174,6 +174,12 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty)) } + ExprKind::Hide { source } => { + let source = this.hir.mirror(source); + + let source = unpack!(block = this.as_operand(block, scope, source)); + block.and(Rvalue::Cast(CastKind::Hide, source, expr.ty)) + } ExprKind::Unsize { source } => { let source = unpack!(block = this.as_operand(block, scope, source)); block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty)) diff --git a/src/librustc_mir/build/expr/category.rs b/src/librustc_mir/build/expr/category.rs index 05a9079cdb1ef..d85c268bf8abc 100644 --- a/src/librustc_mir/build/expr/category.rs +++ b/src/librustc_mir/build/expr/category.rs @@ -72,6 +72,7 @@ impl Category { | ExprKind::ReifyFnPointer { .. } | ExprKind::ClosureFnPointer { .. } | ExprKind::UnsafeFnPointer { .. } + | ExprKind::Hide { .. } | ExprKind::Unsize { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index d2913872fca45..4ff69aa194e9c 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -399,6 +399,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { | ExprKind::ReifyFnPointer { .. } | ExprKind::ClosureFnPointer { .. } | ExprKind::UnsafeFnPointer { .. } + | ExprKind::Hide { .. } | ExprKind::Unsize { .. } | ExprKind::Repeat { .. } | ExprKind::Borrow { .. } diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 48fcdd42ff5e0..f2c987ac60ff0 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -9,19 +9,19 @@ // except according to those terms. use hair::*; -use rustc_data_structures::indexed_vec::Idx; use hair::cx::Cx; use hair::cx::block; use hair::cx::to_ref::ToRef; use hair::util::UserAnnotatedTyHelpers; use rustc::hir::def::{Def, CtorKind}; +use rustc::mir::{BorrowKind}; use rustc::mir::interpret::{GlobalId, ErrorHandled}; use rustc::ty::{self, AdtKind, Ty}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, AutoBorrowMutability}; use rustc::ty::cast::CastKind as TyCastKind; use rustc::hir; use rustc::hir::def_id::LocalDefId; -use rustc::mir::{BorrowKind}; +use rustc_data_structures::indexed_vec::Idx; use syntax_pos::Span; impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { @@ -150,9 +150,8 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, } } Adjust::Borrow(AutoBorrow::RawPtr(m)) => { - // Convert this to a suitable `&foo` and - // then an unsafe coercion. Limit the region to be just this - // expression. + // Convert this to a suitable `&foo` and then an unsafe coercion. + // Limit the region to be just this expression. let region = ty::ReScope(region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node @@ -162,8 +161,8 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, temp_lifetime, ty: cx.tcx.mk_ref(region, ty::TypeAndMut { - ty: expr.ty, - mutbl: m, + ty: expr.ty, + mutbl: m, }), span, kind: ExprKind::Borrow { @@ -181,33 +180,43 @@ fn apply_adjustment<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // To ensure that both implicit and explicit coercions are // handled the same way, we insert an extra layer of indirection here. - // For explicit casts (e.g. 'foo as *const T'), the source of the 'Use' - // will be an ExprKind::Hair with the appropriate cast expression. Here, - // we make our Use source the generated Cast from the original coercion. + // For explicit casts (e.g. `foo as *const T`), the source of the `Use` + // will be an `ExprKind::Hair` with the appropriate cast expression. Here, + // we make our Use source the generated `Cast` from the original coercion. // - // In both cases, this outer 'Use' ensures that the inner 'Cast' is handled by - // as_operand, not by as_rvalue - causing the cast result to be stored in a temporary. - // Ordinary, this is identical to using the cast directly as an rvalue. However, if the - // source of the cast was previously borrowed as mutable, storing the cast in a - // temporary gives the source a chance to expire before the cast is used. For - // structs with a self-referential *mut ptr, this allows assignment to work as + // In both cases, this outer `Use` ensures that the inner 'Cast' is handled by + // `as_operand`, not by `as_rvalue` - causing the cast result to be stored in a + // temporary. Ordinarily, this is identical to using the cast directly as an rvalue. + // However, if the source of the cast was previously borrowed as mutable, storing the + // cast in a temporary gives the source a chance to expire before the cast is used. + // For structs with a self-referential `*mut ptr`, this allows assignment to work as // expected. // - // For example, consider the type 'struct Foo { field: *mut Foo }', - // The method 'fn bar(&mut self) { self.field = self }' - // triggers a coercion from '&mut self' to '*mut self'. In order + // For example, consider the type `struct Foo { field: *mut Foo }`, + // The method `fn bar(&mut self) { self.field = self }` + // triggers a coercion from `&mut self` to `*mut self`. In order // for the assignment to be valid, the implicit borrow - // of 'self' involved in the coercion needs to end before the local - // containing the '*mut T' is assigned to 'self.field' - otherwise, - // we end up trying to assign to 'self.field' while we have another mutable borrow + // of `self` involved in the coercion needs to end before the local + // containing the `*mut T` is assigned to `self.field` -- otherwise, + // we end up trying to assign to `self.field` while we have another mutable borrow // active. // // We only need to worry about this kind of thing for coercions from refs to ptrs, // since they get rid of a borrow implicitly. ExprKind::Use { source: cast_expr.to_ref() } } + Adjust::Hide => { + // See the above comment for `Adjust::Deref`. + if let ExprKind::Block { body } = expr.kind { + if let Some(ref last_expr) = body.expr { + span = last_expr.span; + expr.span = span; + } + } + ExprKind::Hide { source: expr.to_ref() } + } Adjust::Unsize => { - // See the above comment for Adjust::Deref + // See the above comment for `Adjust::Deref`. if let ExprKind::Block { body } = expr.kind { if let Some(ref last_expr) = body.expr { span = last_expr.span; @@ -652,25 +661,25 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, // Check to see if this cast is a "coercion cast", where the cast is actually done // using a coercion (or is a no-op). - let cast = if let Some(&TyCastKind::CoercionCast) = - cx.tables() + let cast = if let Some(&TyCastKind::CoercionCast) = cx + .tables() .cast_kinds() .get(source.hir_id) { // Convert the lexpr to a vexpr. ExprKind::Use { source: source.to_ref() } } else { - // check whether this is casting an enum variant discriminant + // Check whether this is casting an enum variant discriminant // to prevent cycles, we refer to the discriminant initializer // which is always an integer and thus doesn't need to know the - // enum's layout (or its tag type) to compute it during const eval + // enum's layout (or its tag type) to compute it during const eval. // Example: // enum Foo { // A, // B = A as isize + 4, // } // The correct solution would be to add symbolic computations to miri, - // so we wouldn't have to compute and store the actual value + // so we wouldn't have to compute and store the actual value. let var = if let hir::ExprKind::Path(ref qpath) = source.node { let def = cx.tables().qpath_def(qpath, source.hir_id); cx @@ -739,8 +748,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }; if let Some(user_ty) = user_ty { - // NOTE: Creating a new Expr and wrapping a Cast inside of it may be - // inefficient, revisit this when performance becomes an issue. + // NOTE: Creating a new `Expr` and wrapping a `Cast` inside of it may be + // inefficient; revisit this when performance becomes an issue. let cast_expr = Expr { temp_lifetime, ty: expr_ty, diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 3a56d261111ee..2596c6eb635f1 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -10,9 +10,8 @@ //! This module contains the code to convert from the wacky tcx data //! structures into the hair. The `builder` is generally ignorant of -//! the tcx etc, and instead goes through the `Cx` for most of its -//! work. -//! +//! the tcx and whatnot, and instead goes through the `Cx` for most of +//! its work. use hair::*; use hair::util::UserAnnotatedTyHelpers; @@ -77,7 +76,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { // the settings for the crate they are codegened in. let mut check_overflow = attr::contains_name(attrs, "rustc_inherit_overflow_checks"); - // Respect -C overflow-checks. + // Respect `-C overflow-checks` compiler flag. check_overflow |= tcx.sess.overflow_checks(); // Constants always need overflow checks. @@ -130,7 +129,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { ty::Const::from_bool(self.tcx, false) } - // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const + // FIXME: Combine with `rustc_mir::hair::pattern::lit_to_const`. pub fn const_eval_literal( &mut self, lit: &'tcx ast::LitKind, diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 8a24851de8149..b981cde1a1a60 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -193,6 +193,9 @@ pub enum ExprKind<'tcx> { UnsafeFnPointer { source: ExprRef<'tcx>, }, + Hide { + source: ExprRef<'tcx>, + }, Unsize { source: ExprRef<'tcx>, }, diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 06748d60e4583..c749163de3318 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -39,6 +39,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> ) -> EvalResult<'tcx> { use rustc::mir::CastKind::*; match kind { + Hide => { + // TODO: implement + unimplemented!(); + } + Unsize => { self.unsize_into(src, dest)?; } diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs index db055204c0a19..4b9b195fdc1ae 100644 --- a/src/librustc_mir/interpret/step.rs +++ b/src/librustc_mir/interpret/step.rs @@ -152,7 +152,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> use rustc::mir::Rvalue::*; match *rvalue { Use(ref operand) => { - // Avoid recomputing the layout + // Avoid recomputing the layout. let op = self.eval_operand(operand, Some(dest.layout))?; self.copy_op(op, dest)?; } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 4f92ba400481b..b4fda3f3dd040 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -349,7 +349,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { }) } - // FIXME(oli-obk): evaluate static/constant slice lengths + // FIXME(oli-obk): evaluate static/constant slice lengths. Rvalue::Len(_) => None, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(( diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index ca9c4eb9b8bb9..457b47f7b244a 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -642,6 +642,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { Rvalue::Cast(CastKind::ReifyFnPointer, ..) | Rvalue::Cast(CastKind::UnsafeFnPointer, ..) | Rvalue::Cast(CastKind::ClosureFnPointer, ..) | + Rvalue::Cast(CastKind::Hide, ..) | Rvalue::Cast(CastKind::Unsize, ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) => {} @@ -756,11 +757,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { (CastTy::Ptr(_), CastTy::Int(_)) | (CastTy::FnPtr, CastTy::Int(_)) => { if let Mode::Fn = self.mode { - // in normal functions, mark such casts as not promotable + // In normal functions, mark such casts as not promotable. self.add(Qualif::NOT_CONST); } else if !self.tcx.sess.features_untracked().const_raw_ptr_to_usize_cast { - // in const fn and constants require the feature gate - // FIXME: make it unsafe inside const fn and constants + // In const functions and constants require the feature gate. + // FIXME: make it unsafe inside const fn and constants. emit_feature_err( &self.tcx.sess.parse_sess, "const_raw_ptr_to_usize_cast", self.span, GateIssue::Language, @@ -783,11 +784,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { op == BinOp::Offset); if let Mode::Fn = self.mode { - // raw pointer operations are not allowed inside promoteds + // Raw pointer operations are not allowed inside promoteds. self.add(Qualif::NOT_CONST); } else if !self.tcx.sess.features_untracked().const_compare_raw_pointers { - // require the feature gate inside constants and const fn - // FIXME: make it unsafe to use these operations + // Require the feature gate inside constants and const fn. + // FIXME: make it unsafe to use these operations. emit_feature_err( &self.tcx.sess.parse_sess, "const_compare_raw_pointers", @@ -872,16 +873,16 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { | "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" - // no need to check feature gates, intrinsics are only callable from the - // libstd or with forever unstable feature gates + // No need to check feature gates, intrinsics are only callable from the + // libstd or with forever unstable feature gates. => is_const_fn = true, - // special intrinsic that can be called diretly without an intrinsic - // feature gate needs a language feature gate + // Special intrinsic that can be called diretly without an intrinsic + // feature gate needs a language feature gate. "transmute" => { - // never promote transmute calls + // Never promote transmute calls. if self.mode != Mode::Fn { is_const_fn = true; - // const eval transmute calls only with the feature gate + // Const-eval transmute calls only with the feature gate. if !self.tcx.sess.features_untracked().const_transmute { emit_feature_err( &self.tcx.sess.parse_sess, "const_transmute", @@ -900,10 +901,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { } } _ => { - // in normal functions we only care about promotion + // In normal functions we only care about promotion. if self.mode == Mode::Fn { - // never promote const fn calls of - // functions without #[rustc_promotable] + // Never promote const fn calls of + // functions without `#[rustc_promotable]`. if self.tcx.is_promotable_const_fn(def_id) { is_const_fn = true; is_promotable_const_fn = true; @@ -911,19 +912,19 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { is_const_fn = true; } } else { - // stable const fn or unstable const fns with their feature gate - // active + // Stable const fn or unstable const fns with their feature gate + // active. if self.tcx.is_const_fn(def_id) { is_const_fn = true; } else if self.is_const_panic_fn(def_id) { - // check the const_panic feature gate + // Check the `const_panic` feature gate. // FIXME: cannot allow this inside `allow_internal_unstable` because // that would make `panic!` insta stable in constants, since the - // macro is marked with the attr + // macro is marked with the attr. if self.tcx.sess.features_untracked().const_panic { is_const_fn = true; } else { - // don't allow panics in constants without the feature gate + // Don't allow panics in constants without the feature gate. emit_feature_err( &self.tcx.sess.parse_sess, "const_panic", @@ -933,11 +934,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { ); } } else if let Some(feature) = self.tcx.is_unstable_const_fn(def_id) { - // check `#[unstable]` const fns or `#[rustc_const_unstable]` + // Check `#[unstable]` const fns or `#[rustc_const_unstable]` // functions without the feature gate active in this crate to report - // a better error message than the one below + // a better error message than the one below. if self.span.allows_unstable() { - // `allow_internal_unstable` can make such calls stable + // `allow_internal_unstable` can make such calls stable. is_const_fn = true; } else { let mut err = self.tcx.sess.struct_span_err(self.span, @@ -950,7 +951,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { err.emit(); } } else { - // FIXME(#24111) Remove this check when const fn stabilizes + // FIXME(#24111): remove this check when const fn stabilizes. let (msg, note) = if let UnstableFeatures::Disallow = self.tcx.sess.opts.unstable_features { (format!("calls in {}s are limited to \ @@ -1032,7 +1033,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> { }); } - // non-const fn calls. + // non-const fn calls if !is_const_fn { self.qualif = Qualif::NOT_CONST; if self.mode != Mode::Fn { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index 1e19348595057..99c94c84b035f 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -169,6 +169,10 @@ fn check_rvalue( span, "function pointer casts are not allowed in const fn".into(), )), + Rvalue::Cast(CastKind::Hide, _, _) => Err(( + span, + "hiding casts are not allowed in const fn".into(), + )), Rvalue::Cast(CastKind::Unsize, _, _) => Err(( span, "unsizing casts are not allowed in const fn".into(), diff --git a/src/librustc_passes/rvalue_promotion.rs b/src/librustc_passes/rvalue_promotion.rs index ca58239df8eac..86a3abc89175c 100644 --- a/src/librustc_passes/rvalue_promotion.rs +++ b/src/librustc_passes/rvalue_promotion.rs @@ -615,6 +615,7 @@ fn check_adjustments<'a, 'tcx>( Adjust::ClosureFnPointer | Adjust::MutToConstPointer | Adjust::Borrow(_) | + Adjust::Hide | Adjust::Unsize => {} Adjust::Deref(_) => { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 18f8473b5b56d..8c06ebaeed60f 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1361,7 +1361,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { let span = path.span; match path.def { Def::Existential(did) => { - // check for desugared impl trait + // Check for desugared impl trait. assert!(ty::is_impl_trait_defn(tcx, did).is_none()); let item_segment = path.segments.split_last().unwrap(); self.prohibit_generics(item_segment.1); @@ -1398,8 +1398,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> dyn AstConv<'gcx, 'tcx>+'o { tcx.mk_ty_param(index, tcx.hir.name(node_id).as_interned_str()) } Def::SelfTy(_, Some(def_id)) => { - // Self in impl (we know the concrete type). - + // Self in impl. (We know the concrete type.) assert_eq!(opt_self_ty, None); self.prohibit_generics(&path.segments); diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 40f2072079a5a..569119bdd9c15 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -234,7 +234,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { .pat_binding_modes_mut() .insert(pat.hir_id, bm); debug!("check_pat_walk: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); - let local_ty = self.local_ty(pat.span, pat.id).decl_ty; + let local_ty = self.local_ty(pat.span, pat.id); match bm { ty::BindByReference(mutbl) => { // if the binding is like @@ -261,7 +261,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // if there are multiple arms, make sure they all agree on // what the type of the binding `x` ought to be if var_id != pat.id { - let vt = self.local_ty(pat.span, var_id).decl_ty; + let vt = self.local_ty(pat.span, var_id); self.demand_eqtype(pat.span, vt, local_ty); } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index 3bdd038bff19c..f98a5decb547a 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -82,17 +82,18 @@ struct Coerce<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, cause: ObligationCause<'tcx>, use_lub: bool, - /// Determines whether or not allow_two_phase_borrow is set on any + /// Determines whether or not `allow_two_phase_borrow` is set on any /// autoref adjustments we create while coercing. We don't want to /// allow deref coercions to create two-phase borrows, at least initially, /// but we do need two-phase borrows for function argument reborrows. - /// See #47489 and #48598 - /// See docs on the "AllowTwoPhase" type for a more detailed discussion + /// See #47489 and #48598. + /// See docs on the `AllowTwoPhase` type for a more detailed discussion. allow_two_phase: AllowTwoPhase, } impl<'a, 'gcx, 'tcx> Deref for Coerce<'a, 'gcx, 'tcx> { type Target = FnCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { &self.fcx } @@ -161,6 +162,52 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }) } + fn reborrow(&self, source: Ty<'tcx>, target: Ty<'tcx>) + -> Result, Adjustment<'tcx>)>, TypeError<'tcx>> { + Ok(match (&source.sty, &target.sty) { + (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { + coerce_mutbls(mutbl_a, mutbl_b)?; + + let coercion = Coercion(self.cause.span); + let r_borrow = self.next_region_var(coercion); + let mutbl = match mutbl_b { + hir::MutImmutable => AutoBorrowMutability::Immutable, + hir::MutMutable => AutoBorrowMutability::Mutable { + // We don't allow two-phase borrows here, at least for initial + // implementation. If it happens that this coercion is a function argument, + // the reborrow in coerce_borrowed_ptr will pick it up. + allow_two_phase_borrow: AllowTwoPhase::No, + } + }; + Some((Adjustment { + kind: Adjust::Deref(None), + target: ty_a + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), + target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut { + mutbl: mutbl_b, + ty: ty_a + }) + })) + } + (&ty::Ref(_, ty_a, mutbl_a), &ty::RawPtr(ty::TypeAndMut { mutbl: mutbl_b, .. })) => { + coerce_mutbls(mutbl_a, mutbl_b)?; + + Some((Adjustment { + kind: Adjust::Deref(None), + target: ty_a + }, Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), + target: self.tcx.mk_ptr(ty::TypeAndMut { + mutbl: mutbl_b, + ty: ty_a + }) + })) + } + _ => None, + }) + } + fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { let a = self.shallow_resolve(a); debug!("Coerce.tys({:?} => {:?})", a, b); @@ -190,9 +237,20 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { }; } - // Consider coercing the subtype to a DST + // Consider coercing to an opaque type. // - // NOTE: this is wrapped in a `commit_if_ok` because it creates + // Note: this is wrapped in a `commit_if_ok` because it creates + // a "spurious" type variable, and we don't want to have that + // type variable in memory if the coercion fails. + let hide = self.commit_if_ok(|_| self.coerce_hidden(a, b)); + if hide.is_ok() { + debug!("coerce: hide successful"); + return self.coerce_hidden(a, b); + } + + // Consider coercing the subtype to a DST. + // + // Note: this is wrapped in a `commit_if_ok` because it creates // a "spurious" type variable, and we don't want to have that // type variable in memory if the coercion fails. let unsize = self.commit_if_ok(|_| self.coerce_unsized(a, b)); @@ -210,12 +268,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { ty::RawPtr(mt_b) => { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); } - ty::Ref(r_b, ty, mutbl) => { let mt_b = ty::TypeAndMut { ty, mutbl }; return self.coerce_borrowed_pointer(a, b, r_b, mt_b); } - _ => {} } @@ -447,6 +503,48 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { success(adjustments, ty, obligations) } + // T -> impl Bounds, where T satisfies Bounds + fn coerce_hidden(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> { + debug!("coerce_hidden(source={:?}, target={:?})", source, target); + + let target_predicates = if let ty::Opaque(def_id, substs) = target.sty { + self.instantiate_bounds(self.cause.span, def_id, substs) + } else { + debug!("coerce_hidden: target is not opaque type"); + return Err(TypeError::Mismatch); + }; + + // Handle reborrows before checking target is subtype of source. + let reborrow = self.reborrow(source, target)?; + + // Set up either a subtyping or a LUB relationship between + // the opaque type and the expected type. + // We only have the latter, so we use an inference variable + // for the former and let type inference do the rest. + let origin = TypeVariableOrigin::MiscVariable(self.cause.span); + let coerce_target = self.next_ty_var(origin); + let mut coercion = self.unify_and(coerce_target, target, |target| { + let hide = Adjustment { + kind: Adjust::Hide, + target + }; + match reborrow { + None => vec![hide], + Some((ref deref, ref autoref)) => { + vec![deref.clone(), autoref.clone(), hide] + } + } + })?; + + // Create the obligations for `Source` satisfying the target predicates. + let cause = ObligationCause::misc(self.cause.span, self.fcx.body_id); + let obligations = traits::predicates_for_generics(cause, + self.fcx.param_env, + &target_predicates); + coercion.obligations.extend(obligations); + + Ok(coercion) + } // &[T; n] or &mut [T; n] -> &[T] // or &mut [T; n] -> &mut [T] @@ -459,7 +557,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let (unsize_did, coerce_unsized_did) = if let (Some(u), Some(cu)) = traits { (u, cu) } else { - debug!("Missing Unsize or CoerceUnsized traits"); + debug!("coerce_unsized: missing Unsize or CoerceUnsized traits"); return Err(TypeError::Mismatch); }; @@ -469,51 +567,10 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { // that, at which point we will need extra checks on the target here. // Handle reborrows before selecting `Source: CoerceUnsized`. - let reborrow = match (&source.sty, &target.sty) { - (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { - coerce_mutbls(mutbl_a, mutbl_b)?; - - let coercion = Coercion(self.cause.span); - let r_borrow = self.next_region_var(coercion); - let mutbl = match mutbl_b { - hir::MutImmutable => AutoBorrowMutability::Immutable, - hir::MutMutable => AutoBorrowMutability::Mutable { - // We don't allow two-phase borrows here, at least for initial - // implementation. If it happens that this coercion is a function argument, - // the reborrow in coerce_borrowed_ptr will pick it up. - allow_two_phase_borrow: AllowTwoPhase::No, - } - }; - Some((Adjustment { - kind: Adjust::Deref(None), - target: ty_a - }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)), - target: self.tcx.mk_ref(r_borrow, ty::TypeAndMut { - mutbl: mutbl_b, - ty: ty_a - }) - })) - } - (&ty::Ref(_, ty_a, mt_a), &ty::RawPtr(ty::TypeAndMut { mutbl: mt_b, .. })) => { - coerce_mutbls(mt_a, mt_b)?; - - Some((Adjustment { - kind: Adjust::Deref(None), - target: ty_a - }, Adjustment { - kind: Adjust::Borrow(AutoBorrow::RawPtr(mt_b)), - target: self.tcx.mk_ptr(ty::TypeAndMut { - mutbl: mt_b, - ty: ty_a - }) - })) - } - _ => None, - }; + let reborrow = self.reborrow(source, target)?; let coerce_source = reborrow.as_ref().map_or(source, |&(_, ref r)| r.target); - // Setup either a subtyping or a LUB relationship between + // Set up either a subtyping or a LUB relationship between // the `CoerceUnsized` target type and the expected type. // We only have the latter, so we use an inference variable // for the former and let type inference do the rest. @@ -535,7 +592,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> { let mut selcx = traits::SelectionContext::new(self); // Create an obligation for `Source: CoerceUnsized`. - let cause = ObligationCause::misc(self.cause.span, self.body_id); + let cause = ObligationCause::misc(self.cause.span, self.fcx.body_id); // Use a FIFO queue for this custom fulfillment procedure. // @@ -776,7 +833,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { Ok(target) } - /// Same as `try_coerce()`, but without side-effects. + /// Same as `try_coerce`, but without side-effects. pub fn can_coerce(&self, expr_ty: Ty<'tcx>, target: Ty<'tcx>) -> bool { let source = self.resolve_type_vars_with_obligations(expr_ty); debug!("coercion::can({:?} -> {:?})", source, target); diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index 0a196834cb494..21eca3496ca01 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -89,11 +89,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ty } - // Checks that the type of `expr` can be coerced to `expected`. - // - // NB: This code relies on `self.diverges` to be accurate. In - // particular, assignments to `!` will be permitted if the - // diverges flag is currently "always". + /// Checks that the type of `expr` can be coerced to `expected`. + /// + /// N.B., this code relies on `self.diverges` to be accurate. In + /// particular, assignments to `!` will be permitted if the + /// diverges flag is currently "always". pub fn demand_coerce_diag(&self, expr: &hir::Expr, checked_ty: Ty<'tcx>, @@ -111,7 +111,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let expr_ty = self.resolve_type_vars_with_obligations(checked_ty); let mut err = self.report_mismatched_types(&cause, expected, expr_ty, e); - // If the expected type is an enum (Issue #55250) with any variants whose + // If the expected type is an enum (issue #55250) with any variants whose // sole field is of the found type, suggest such variants. (Issue #42764) if let ty::Adt(expected_adt, substs) = expected.sty { if expected_adt.is_enum() { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 7dfdb926c60ef..7602cf399c54e 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -12,10 +12,9 @@ # check.rs -Within the check phase of type check, we check each item one at a time +Within the check phase of type checking, we check each item one at a time (bodies of function expressions are checked as part of the containing -function). Inference is used to supply types wherever they are -unknown. +function). Inference is used to supply types wherever they are unknown. By far the most complex case is checking the body of a function. This can be broken down into several distinct phases: @@ -155,13 +154,6 @@ mod generator_interior; mod intrinsic; mod op; -/// The type of a local binding, including the revealed type for anon types. -#[derive(Copy, Clone)] -pub struct LocalTy<'tcx> { - decl_ty: Ty<'tcx>, - revealed_ty: Ty<'tcx> -} - /// A wrapper for InferCtxt's `in_progress_tables` field. #[derive(Copy, Clone)] struct MaybeInProgressTables<'a, 'tcx: 'a> { @@ -188,7 +180,7 @@ impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { } } -/// closures defined within the function. For example: +/// Closures defined within the function. For example: /// /// fn foo() { /// bar(move|| { ... }) @@ -202,7 +194,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tables: MaybeInProgressTables<'a, 'tcx>, - locals: RefCell>>, + locals: RefCell>>, fulfillment_cx: RefCell>>, @@ -238,6 +230,7 @@ pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> { type Target = InferCtxt<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { &self.infcx } @@ -494,8 +487,8 @@ impl Diverges { pub struct BreakableCtxt<'gcx: 'tcx, 'tcx> { may_break: bool, - // this is `null` for loops where break with a value is illegal, - // such as `while`, `for`, and `while let` + // This is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let`. coerce: Option>, } @@ -582,6 +575,7 @@ pub struct FnCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { impl<'a, 'gcx, 'tcx> Deref for FnCtxt<'a, 'gcx, 'tcx> { type Target = Inherited<'a, 'gcx, 'tcx>; + fn deref(&self) -> &Self::Target { &self.inh } @@ -871,19 +865,10 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); - let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.instantiate_opaque_types_from_value( - id, - &expected_type - ) - } else { - expected_type - }; - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor { fcx: &fcx, parent_id: id, }.visit_body(body); + GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); - fcx.check_expr_coercable_to_type(&body.value, revealed_ty); + fcx.check_expr_coercable_to_type(&body.value, expected_type); fcx }; @@ -932,25 +917,21 @@ fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) { struct GatherLocalsVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'gcx, 'tcx>, - parent_id: ast::NodeId, } impl<'a, 'gcx, 'tcx> GatherLocalsVisitor<'a, 'gcx, 'tcx> { - fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { + fn assign(&mut self, span: Span, nid: ast::NodeId, ty_opt: Option>) -> Ty<'tcx> { match ty_opt { None => { - // infer the variable's type + // Infer the variable's type. let var_ty = self.fcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); - self.fcx.locals.borrow_mut().insert(nid, LocalTy { - decl_ty: var_ty, - revealed_ty: var_ty - }); + self.fcx.locals.borrow_mut().insert(nid, var_ty); var_ty } Some(typ) => { - // take type that the user specified + // Use the type that the user specified. self.fcx.locals.borrow_mut().insert(nid, typ); - typ.revealed_ty + typ } } } @@ -963,34 +944,24 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { // Add explicitly-declared locals. fn visit_local(&mut self, local: &'gcx hir::Local) { - let local_ty = match local.ty { + let o_ty = match local.ty { Some(ref ty) => { let o_ty = self.fcx.to_ty(&ty); - let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value( - self.parent_id, - &o_ty - ) - } else { - o_ty - }; - - let c_ty = self.fcx.inh.infcx.canonicalize_user_type_annotation(&revealed_ty); - debug!("visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", - ty.hir_id, o_ty, revealed_ty, c_ty); + let c_ty = self.fcx.inh.infcx.canonicalize_response(&o_ty); + debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, c_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); - Some(LocalTy { decl_ty: o_ty, revealed_ty }) + Some(o_ty) }, None => None, }; - self.assign(local.span, local.id, local_ty); + self.assign(local.span, local.id, o_ty); - debug!("Local variable {:?} is assigned type {}", + debug!("visit_local: variable {:?} is assigned type {}", local.pat, self.fcx.ty_to_string( - self.fcx.locals.borrow().get(&local.id).unwrap().clone().decl_ty)); + self.fcx.locals.borrow().get(&local.id).unwrap().clone())); intravisit::walk_local(self, local); } @@ -1004,10 +975,10 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { traits::VariableType(p.id)); } - debug!("Pattern binding {} is assigned to {} with type {:?}", + debug!("visit_pat: pattern binding {} is assigned to {} with type {:?}", ident, self.fcx.ty_to_string( - self.fcx.locals.borrow().get(&p.id).unwrap().clone().decl_ty), + self.fcx.locals.borrow().get(&p.id).unwrap().clone()), var_ty); } intravisit::walk_pat(self, p); @@ -1051,14 +1022,16 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, debug!("check_fn(sig={:?}, fn_id={}, param_env={:?})", fn_sig, fn_id, param_env); - // Create the function context. This is either derived from scratch or, + // Create the function context. This is either derived from scratch or, // in the case of closures, based on the outer context. let mut fcx = FnCtxt::new(inherited, param_env, body.value.id); *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + let fn_def_id = fcx.tcx.hir.local_def_id(fn_id); let declared_ret_ty = fn_sig.output(); fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - let revealed_ret_ty = fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty); + let revealed_ret_ty = fcx.instantiate_opaque_types_from_return_value( + fn_def_id, &declared_ret_ty); fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); fn_sig = fcx.tcx.mk_fn_sig( fn_sig.inputs().iter().cloned(), @@ -1076,9 +1049,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>, fcx.yield_ty = Some(yield_ty); } - let outer_def_id = fcx.tcx.closure_base_def_id(fcx.tcx.hir.local_def_id(fn_id)); - let outer_node_id = fcx.tcx.hir.as_local_node_id(outer_def_id).unwrap(); - GatherLocalsVisitor { fcx: &fcx, parent_id: outer_node_id, }.visit_body(body); + GatherLocalsVisitor { fcx: &fcx, }.visit_body(body); // Add formal parameters. for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) { @@ -2074,7 +2045,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { format!("{:?}", self_ptr) } - pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> LocalTy<'tcx> { + pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> { self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| span_bug!(span, "no type for local variable {}", self.tcx.hir.node_to_string(nid)) @@ -2274,16 +2245,16 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { result } - /// Replace the opaque types from the given value with type variables, - /// and records the `OpaqueTypeMap` for later use during writeback. See + /// Replace the opaque types from the return value of the + /// function with type variables and records the `OpaqueTypeMap` for + /// later use during writeback. See /// `InferCtxt::instantiate_opaque_types` for more details. - fn instantiate_opaque_types_from_value>( + fn instantiate_opaque_types_from_return_value>( &self, - parent_id: ast::NodeId, + parent_def_id: DefId, value: &T, ) -> T { - let parent_def_id = self.tcx.hir.local_def_id(parent_id); - debug!("instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", + debug!("instantiate_opaque_types_from_return_value(parent_def_id={:?}, value={:?})", parent_def_id, value); @@ -3724,7 +3695,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { adt_ty } - /// Invariant: /// If an expression has any sub-expressions that result in a type error, /// inspecting that expression's type with `ty.references_error()` will return @@ -3776,7 +3746,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { self.diverges.set(self.diverges.get() | old_diverges); self.has_errors.set(self.has_errors.get() | old_has_errors); - debug!("type of {} is...", self.tcx.hir.node_to_string(expr.id)); + debug!("type of {} is ...", self.tcx.hir.node_to_string(expr.id)); debug!("... {:?}, expected is {:?}", ty, expected); ty @@ -3809,7 +3779,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { let referent_ty = self.check_expr_with_expectation(subexpr, expected_inner); tcx.mk_box(referent_ty) } - hir::ExprKind::Lit(ref lit) => { self.check_lit(&lit, expected) } @@ -4003,7 +3972,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { ctxt.may_break = true; - // the type of a `break` is always `!`, since it diverges + // The type of a `break` is always `!`, since it diverges. tcx.types.never } else { // Otherwise, we failed to find the enclosing loop; @@ -4467,12 +4436,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { // See #44848. let ref_bindings = local.pat.contains_explicit_ref_binding(); - let local_ty = self.local_ty(init.span, local.id).revealed_ty; + let local_ty = self.local_ty(init.span, local.id); if let Some(m) = ref_bindings { // Somewhat subtle: if we have a `ref` binding in the pattern, // we want to avoid introducing coercions for the RHS. This is // both because it helps preserve sanity and, in the case of - // ref mut, for soundness (issue #23116). In particular, in + // `ref mut`, for soundness (issue #23116). In particular, in // the latter case, we need to be clear that the type of the // referent for the reference that results is *equal to* the // type of the place it is referencing, and not some @@ -4486,7 +4455,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } pub fn check_decl_local(&self, local: &'gcx hir::Local) { - let t = self.local_ty(local.span, local.id).decl_ty; + let t = self.local_ty(local.span, local.id); self.write_ty(local.hir_id, t); if let Some(ref init) = local.init { @@ -5062,7 +5031,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { match def { Def::Local(nid) | Def::Upvar(nid, ..) => { - let ty = self.local_ty(span, nid).decl_ty; + let ty = self.local_ty(span, nid); let ty = self.normalize_associated_types_in(span, &ty); self.write_ty(self.tcx.hir.node_to_hir_id(node_id), ty); return (ty, def); @@ -5307,7 +5276,9 @@ pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if own_counts.types == 0 { return; } + // Make a vector of booleans initially false, set to true when used. + // FIXME: use `BitSet` here instead. let mut types_used = vec![false; own_counts.types]; for leaf_ty in ty.walk() { diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index d968bf222aa09..672a1328ac91b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -8,9 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Type resolution: the phase that finds all the types in the AST with -// unresolved type variables and replaces "ty_var" types with their -// substitutions. +/* + +# Writeback + +This phase of type resolution finds all the types in the AST with +unresolved type variables and replaces "ty_var" types with their +substitutions. + +*/ use check::FnCtxt; use rustc::hir; @@ -286,7 +292,7 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> { fn visit_local(&mut self, l: &'gcx hir::Local) { intravisit::walk_local(self, l); - let var_ty = self.fcx.local_ty(l.span, l.id).decl_ty; + let var_ty = self.fcx.local_ty(l.span, l.id); let var_ty = self.resolve(&var_ty, &l.span); self.write_ty_to_tables(l.hir_id, var_ty); } @@ -425,31 +431,31 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { instantiated_ty, ) } else { - // prevent + // Prevent // * `fn foo() -> Foo` // * `fn foo() -> Foo` - // from being defining + // from being defining. // Also replace all generic params with the ones from the existential type - // definition so + // definition so that // ```rust // existential type Foo: 'static; // fn foo() -> Foo { .. } // ``` - // figures out the concrete type with `U`, but the stored type is with `T` + // figures out the concrete type with `U`, but the stored type is with `T`. instantiated_ty.fold_with(&mut BottomUpFolder { tcx: self.tcx().global_tcx(), fldop: |ty| { - trace!("checking type {:?}: {:#?}", ty, ty.sty); - // find a type parameter + trace!("visit_opaque_types: checking type {:?}: {:#?}", ty, ty.sty); + // Find a type parameter. if let ty::Param(..) = ty.sty { - // look it up in the substitution list + // Look it up in the substitution list. assert_eq!(opaque_defn.substs.len(), generics.params.len()); for (subst, param) in opaque_defn.substs.iter().zip(&generics.params) { if let UnpackedKind::Type(subst) = subst.unpack() { if subst == ty { - // found it in the substitution list, replace with the - // parameter from the existential type + // Found it in the substitution list, replace with the + // parameter from the existential type. return self.tcx() .global_tcx() .mk_ty_param(param.index, param.name); @@ -520,8 +526,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.sty { if def_id == defin_ty_def_id { - // Concrete type resolved to the existential type itself - // Force a cycle error + // Concrete type itself resolved to the existential type. + // Force a cycle error. self.tcx().at(span).type_of(defin_ty_def_id); } } @@ -533,8 +539,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> { if old != definition_ty { span_bug!( span, - "visit_opaque_types tried to write \ - different types for the same existential type: {:?}, {:?}, {:?}", + "visit_opaque_types: tried to write different types \ + for the same existential type: {:?}, {:?}, {:?}", def_id, definition_ty, old, diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index be09cfce8cae6..f5f0ae7af055c 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1109,7 +1109,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx ty }) } -fn report_assoc_ty_on_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) { +fn report_assoc_ty_in_inherent_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span) { span_err!( tcx.sess, span, @@ -1148,7 +1148,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { .impl_trait_ref(tcx.hir.get_parent_did(node_id)) .is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); + report_assoc_ty_in_inherent_impl(tcx, item.span); } find_existential_constraints(tcx, def_id) @@ -1158,7 +1158,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { .impl_trait_ref(tcx.hir.get_parent_did(node_id)) .is_none() { - report_assoc_ty_on_inherent_impl(tcx, item.span); + report_assoc_ty_in_inherent_impl(tcx, item.span); } icx.to_ty(ty) @@ -1184,7 +1184,7 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { impl_trait_fn: None, .. }) => find_existential_constraints(tcx, def_id), - // existential types desugared from impl Trait + // existential types desugared from `impl Trait` ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(owner), .. @@ -1194,17 +1194,8 @@ fn type_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Ty<'tcx> { .get(&def_id) .cloned() .unwrap_or_else(|| { - // This can occur if some error in the - // owner fn prevented us from populating - // the `concrete_existential_types` table. - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "owner {:?} has no existential type for {:?} in its tables", - owner, def_id, - ), - ); - tcx.types.err + let substs = Substs::identity_for_item(tcx, def_id); + tcx.mk_opaque(def_id, substs) }) } ItemKind::Trait(..) @@ -1330,7 +1321,7 @@ fn find_existential_constraints<'a, 'tcx>( impl<'a, 'tcx> ConstraintLocator<'a, 'tcx> { fn check(&mut self, def_id: DefId) { trace!("checking {:?}", def_id); - // don't try to check items that cannot possibly constrain the type + // Don't try to check items that cannot possibly constrain the type. if !self.tcx.has_typeck_tables(def_id) { trace!("no typeck tables for {:?}", def_id); return; @@ -1342,11 +1333,11 @@ fn find_existential_constraints<'a, 'tcx>( .get(&self.def_id) .cloned(); if let Some(ty) = ty { - // FIXME(oli-obk): trace the actual span from inference to improve errors + // FIXME(oli-obk): trace the actual span from inference to improve errors. let span = self.tcx.def_span(def_id); if let Some((prev_span, prev_ty)) = self.found { if ty != prev_ty { - // found different concrete types for the existential type + // Found different concrete types for the existential type. let mut err = self.tcx.sess.struct_span_err( span, "defining existential type use differs from previous", @@ -1365,22 +1356,25 @@ fn find_existential_constraints<'a, 'tcx>( fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> { intravisit::NestedVisitorMap::All(&self.tcx.hir) } + fn visit_item(&mut self, it: &'tcx Item) { let def_id = self.tcx.hir.local_def_id(it.id); - // the existential type itself or its children are not within its reveal scope + // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { self.check(def_id); intravisit::walk_item(self, it); } } + fn visit_impl_item(&mut self, it: &'tcx ImplItem) { let def_id = self.tcx.hir.local_def_id(it.id); - // the existential type itself or its children are not within its reveal scope + // The existential type itself or its children are not within its reveal scope. if def_id != self.def_id { self.check(def_id); intravisit::walk_impl_item(self, it); } } + fn visit_trait_item(&mut self, it: &'tcx TraitItem) { let def_id = self.tcx.hir.local_def_id(it.id); self.check(def_id); @@ -1705,7 +1699,7 @@ fn explicit_predicates_of<'a, 'tcx>( let substs = Substs::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); - // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. + // Collect the bounds, i.e. the `A + B + 'c` in `impl A + B + 'c`. let bounds = compute_bounds( &icx, opaque_ty, @@ -1750,7 +1744,7 @@ fn explicit_predicates_of<'a, 'tcx>( let substs = Substs::identity_for_item(tcx, def_id); let opaque_ty = tcx.mk_opaque(def_id, substs); - // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`. + // Collect the bounds, i.e. the `A + B + 'c` in `impl A + B + 'c`. let bounds = compute_bounds( &icx, opaque_ty,