diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c38b3510a0c..84afdd53cf4 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -1739,7 +1739,7 @@ specified exit code, use `std::process::exit`. E0562: r##" Abstract return types (written `impl Trait` for some trait `Trait`) are only -allowed as function and inherent impl return types or binding types. +allowed as function and inherent impl return types. Erroneous code example: @@ -1754,8 +1754,7 @@ fn main() { } ``` -Make sure `impl Trait` only appears in return-type position or as the type of a -binding. +Make sure `impl Trait` only appears in return-type position. ``` fn count_to_n(n: usize) -> impl Iterator { diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 275ca6e1694..f25a17304f9 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -1284,12 +1284,18 @@ impl<'a> LoweringContext<'a> { )) } ImplTraitContext::Disallowed => { + let allowed_in = if self.sess.features_untracked() + .impl_trait_in_bindings { + "bindings or function and inherent method return types" + } else { + "function and inherent method return types" + }; span_err!( self.sess, t.span, E0562, - "`impl Trait` not allowed outside of function \ - and inherent method return types or bindings" + "`impl Trait` not allowed outside of {}", + allowed_in, ); hir::TyKind::Err } @@ -2206,8 +2212,10 @@ impl<'a> LoweringContext<'a> { let impl_trait_ty = self.lower_existential_impl_trait( span, Some(fn_def_id), return_impl_trait_id, |this| { let output_ty = match output { - FunctionRetTy::Ty(ty) => - this.lower_ty(ty, ImplTraitContext::Existential(Some(fn_def_id))), + FunctionRetTy::Ty(ty) => { + let impl_trait_owner_id = *this.current_impl_trait_owner.last().unwrap(); + this.lower_ty(ty, ImplTraitContext::Existential(Some(impl_trait_owner_id))) + } FunctionRetTy::Default(span) => { let LoweredNodeId { node_id, hir_id } = this.next_id(); P(hir::Ty { @@ -2702,14 +2710,31 @@ impl<'a> LoweringContext<'a> { ItemKind::Static(ref t, m, ref e) => { let value = self.lower_body(None, |this| this.lower_expr(e)); hir::ItemKind::Static( - self.lower_ty(t, ImplTraitContext::Disallowed), + self.lower_ty( + t, + if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::Existential(None) + } else { + ImplTraitContext::Disallowed + } + ), self.lower_mutability(m), value, ) } ItemKind::Const(ref t, ref e) => { let value = self.lower_body(None, |this| this.lower_expr(e)); - hir::ItemKind::Const(self.lower_ty(t, ImplTraitContext::Disallowed), value) + hir::ItemKind::Const( + self.lower_ty( + t, + if self.sess.features_untracked().impl_trait_in_bindings { + ImplTraitContext::Existential(None) + } else { + ImplTraitContext::Disallowed + } + ), + value + ) } ItemKind::Fn(ref decl, header, ref generics, ref body) => { let fn_def_id = self.resolver.definitions().local_def_id(id); @@ -3258,6 +3283,22 @@ impl<'a> LoweringContext<'a> { } ids }, + ItemKind::Static(ref ty, ..) => { + let mut ids = smallvec![hir::ItemId { id: i.id }]; + if self.sess.features_untracked().impl_trait_in_bindings { + let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; + visitor.visit_ty(ty); + } + ids + }, + ItemKind::Const(ref ty, ..) => { + let mut ids = smallvec![hir::ItemId { id: i.id }]; + if self.sess.features_untracked().impl_trait_in_bindings { + let mut visitor = ImplTraitTypeIdVisitor { ids: &mut ids }; + visitor.visit_ty(ty); + } + ids + }, _ => smallvec![hir::ItemId { id: i.id }], } } @@ -3817,8 +3858,8 @@ impl<'a> LoweringContext<'a> { } ExprKind::Block(ref blk, opt_label) => { hir::ExprKind::Block(self.lower_block(blk, - opt_label.is_some()), - self.lower_label(opt_label)) + opt_label.is_some()), + self.lower_label(opt_label)) } ExprKind::Assign(ref el, ref er) => { hir::ExprKind::Assign(P(self.lower_expr(el)), P(self.lower_expr(er))) diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 8f84fb7e391..98042e18d32 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -361,7 +361,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, let tcx = relation.tcx(); let a_sty = &a.sty; let b_sty = &b.sty; - debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + debug!("super_relate_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); match (a_sty, b_sty) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => diff --git a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs index d3b215fa070..acde4587d77 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/input_output.rs @@ -17,15 +17,8 @@ //! `RETURN_PLACE` the MIR arguments) are always fully normalized (and //! contain revealed `impl Trait` values). -use borrow_check::nll::renumber; -use borrow_check::nll::type_check::free_region_relations::UniversalRegionRelations; use borrow_check::nll::universal_regions::UniversalRegions; -use rustc::hir::def_id::DefId; -use rustc::infer::InferOk; use rustc::mir::*; -use rustc::traits::query::type_op::custom::CustomTypeOp; -use rustc::traits::{ObligationCause, PredicateObligations}; -use rustc::ty::subst::Subst; use rustc::ty::Ty; use rustc_data_structures::indexed_vec::Idx; @@ -37,16 +30,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { pub(super) fn equate_inputs_and_outputs( &mut self, mir: &Mir<'tcx>, - mir_def_id: DefId, universal_regions: &UniversalRegions<'tcx>, - universal_region_relations: &UniversalRegionRelations<'tcx>, normalized_inputs_and_output: &[Ty<'tcx>], ) { - let tcx = self.infcx.tcx; - let (&normalized_output_ty, normalized_input_tys) = normalized_inputs_and_output.split_last().unwrap(); - let infcx = self.infcx; // Equate expected input tys with those in the MIR. let argument_locals = (1..).map(Local::new); @@ -77,111 +65,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { // Return types are a bit more complex. They may contain existential `impl Trait` // types. - let param_env = self.param_env; let mir_output_ty = mir.local_decls[RETURN_PLACE].ty; let output_span = mir.local_decls[RETURN_PLACE].source_info.span; - let opaque_type_map = - self.fully_perform_op( - Locations::All(output_span), - ConstraintCategory::BoringNoLocation, - CustomTypeOp::new( - |infcx| { - let mut obligations = ObligationAccumulator::default(); - - let dummy_body_id = ObligationCause::dummy().body_id; - let (output_ty, opaque_type_map) = - obligations.add(infcx.instantiate_opaque_types( - mir_def_id, - dummy_body_id, - param_env, - &normalized_output_ty, - )); - debug!( - "equate_inputs_and_outputs: instantiated output_ty={:?}", - output_ty - ); - debug!( - "equate_inputs_and_outputs: opaque_type_map={:#?}", - opaque_type_map - ); - - debug!( - "equate_inputs_and_outputs: mir_output_ty={:?}", - mir_output_ty - ); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(output_ty, mir_output_ty)?, - ); - - for (&opaque_def_id, opaque_decl) in &opaque_type_map { - let opaque_defn_ty = tcx.type_of(opaque_def_id); - let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); - let opaque_defn_ty = renumber::renumber_regions( - infcx, - &opaque_defn_ty, - ); - debug!( - "equate_inputs_and_outputs: concrete_ty={:?}", - opaque_decl.concrete_ty - ); - debug!("equate_inputs_and_outputs: opaque_defn_ty={:?}", - opaque_defn_ty); - obligations.add( - infcx - .at(&ObligationCause::dummy(), param_env) - .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, - ); - } - - debug!("equate_inputs_and_outputs: equated"); - - Ok(InferOk { - value: Some(opaque_type_map), - obligations: obligations.into_vec(), - }) - }, - || "input_output".to_string(), - ), - ).unwrap_or_else(|terr| { - span_mirbug!( - self, - Location::START, - "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", - normalized_output_ty, - mir_output_ty, - terr - ); - None - }); - - // Finally, if we instantiated the opaque types successfully, we - // have to solve any bounds (e.g., `-> impl Iterator` needs to - // prove that `T: Iterator` where `T` is the type we - // instantiated it with). - if let Some(opaque_type_map) = opaque_type_map { - for (opaque_def_id, opaque_decl) in opaque_type_map { - self.fully_perform_op( - Locations::All(infcx.tcx.def_span(opaque_def_id)), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |_cx| { - infcx.constrain_opaque_type( - opaque_def_id, - &opaque_decl, - universal_region_relations - ); - Ok(InferOk { - value: (), - obligations: vec![], - }) - }, - || "opaque_type_map".to_string(), - ), - ).unwrap(); - } - } + if let Err(terr) = self.eq_opaque_type_and_type( + mir_output_ty, + normalized_output_ty, + Locations::All(output_span), + ConstraintCategory::BoringNoLocation, + ) { + span_mirbug!( + self, + Location::START, + "equate_inputs_and_outputs: `{:?}=={:?}` failed with `{:?}`", + normalized_output_ty, + mir_output_ty, + terr + ); + }; } fn equate_normalized_input_or_output(&mut self, a: Ty<'tcx>, b: Ty<'tcx>, span: Span) { @@ -204,20 +104,3 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { } } } - -#[derive(Debug, Default)] -struct ObligationAccumulator<'tcx> { - obligations: PredicateObligations<'tcx>, -} - -impl<'tcx> ObligationAccumulator<'tcx> { - fn add(&mut self, value: InferOk<'tcx, T>) -> T { - let InferOk { value, obligations } = value; - self.obligations.extend(obligations); - value - } - - fn into_vec(self) -> PredicateObligations<'tcx> { - self.obligations - } -} 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 250db4d15e6..8d260e0970a 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -22,6 +22,7 @@ use borrow_check::nll::type_check::free_region_relations::{ }; use borrow_check::nll::universal_regions::UniversalRegions; use borrow_check::nll::ToRegionVid; +use borrow_check::nll::renumber; use dataflow::move_paths::MoveData; use dataflow::FlowAtLocation; use dataflow::MaybeInitializedPlaces; @@ -29,15 +30,18 @@ use rustc::hir; use rustc::hir::def_id::DefId; use rustc::infer::canonical::QueryRegionConstraint; use rustc::infer::region_constraints::GenericKind; -use rustc::infer::{InferCtxt, LateBoundRegionConversionTime}; +use rustc::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime}; use rustc::mir::interpret::EvalErrorKind::BoundsCheck; use rustc::mir::tcx::PlaceTy; use rustc::mir::visit::{PlaceContext, Visitor}; use rustc::mir::*; +use rustc::traits::{ObligationCause, PredicateObligations}; use rustc::traits::query::type_op; +use rustc::traits::query::type_op::custom::CustomTypeOp; use rustc::traits::query::{Fallible, NoSolution}; use rustc::ty::fold::TypeFoldable; use rustc::ty::{self, CanonicalTy, RegionVid, ToPolyTraitRef, Ty, TyCtxt, TyKind}; +use rustc::ty::subst::Subst; use std::fmt; use std::rc::Rc; use syntax_pos::{Span, DUMMY_SP}; @@ -155,12 +159,11 @@ pub(crate) fn type_check<'gcx, 'tcx>( ®ion_bound_pairs, Some(implicit_region_bound), Some(&mut borrowck_context), + Some(&universal_region_relations), |cx| { cx.equate_inputs_and_outputs( mir, - mir_def_id, universal_regions, - &universal_region_relations, &normalized_inputs_and_output, ); liveness::generate(cx, mir, elements, flow_inits, move_data); @@ -182,6 +185,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>( region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, mut extra: impl FnMut(&mut TypeChecker<'a, 'gcx, 'tcx>) -> R, ) -> R where { let mut checker = TypeChecker::new( @@ -192,6 +196,7 @@ fn type_check_internal<'a, 'gcx, 'tcx, R>( region_bound_pairs, implicit_region_bound, borrowck_context, + universal_region_relations, ); let errors_reported = { let mut verifier = TypeVerifier::new(&mut checker, mir); @@ -692,6 +697,7 @@ struct TypeChecker<'a, 'gcx: 'tcx, 'tcx: 'a> { implicit_region_bound: Option>, reported_errors: FxHashSet<(Ty<'tcx>, Span)>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, } struct BorrowCheckContext<'a, 'tcx: 'a> { @@ -799,6 +805,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { region_bound_pairs: &'a [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, borrowck_context: Option<&'a mut BorrowCheckContext<'a, 'tcx>>, + universal_region_relations: Option<&'a UniversalRegionRelations<'tcx>>, ) -> Self { TypeChecker { infcx, @@ -810,6 +817,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: FxHashSet(), + universal_region_relations, } } @@ -883,6 +891,23 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) } + fn sub_types_or_anon( + &mut self, + sub: Ty<'tcx>, + sup: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + if let Err(terr) = self.sub_types(sub, sup, locations) { + if let TyKind::Opaque(..) = sup.sty { + return self.eq_opaque_type_and_type(sub, sup, locations, category); + } else { + return Err(terr); + } + } + Ok(()) + } + fn eq_types( &mut self, a: Ty<'tcx>, @@ -919,6 +944,111 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ) } + fn eq_opaque_type_and_type( + &mut self, + revealed_ty: Ty<'tcx>, + anon_ty: Ty<'tcx>, + locations: Locations, + category: ConstraintCategory, + ) -> Fallible<()> { + let infcx = self.infcx; + let tcx = infcx.tcx; + let param_env = self.param_env; + let mir_def_id = self.mir_def_id; + let opaque_type_map = + self.fully_perform_op( + locations, + CustomTypeOp::new( + |infcx| { + let mut obligations = ObligationAccumulator::default(); + + let dummy_body_id = ObligationCause::dummy().body_id; + let (output_ty, opaque_type_map) = + obligations.add(infcx.instantiate_opaque_types( + mir_def_id, + dummy_body_id, + param_env, + &anon_ty, + )); + debug!( + "eq_opaque_type_and_type: \ + instantiated output_ty={:?} \ + opaque_type_map={:#?} \ + revealed_ty={:?}", + output_ty, + opaque_type_map, + revealed_ty + ); + obligations.add( + infcx + .at(&ObligationCause::dummy(), param_env) + .eq(output_ty, revealed_ty)?, + ); + + for (&opaque_def_id, opaque_decl) in &opaque_type_map { + let opaque_defn_ty = tcx.type_of(opaque_def_id); + let opaque_defn_ty = opaque_defn_ty.subst(tcx, opaque_decl.substs); + let opaque_defn_ty = renumber::renumber_regions( + infcx, + &opaque_defn_ty, + ); + debug!( + "eq_opaque_type_and_type: concrete_ty={:?} opaque_defn_ty={:?}", + opaque_decl.concrete_ty, + opaque_defn_ty + ); + obligations.add( + infcx + .at(&ObligationCause::dummy(), param_env) + .eq(opaque_decl.concrete_ty, opaque_defn_ty)?, + ); + } + + debug!("eq_opaque_type_and_type: equated"); + + Ok(InferOk { + value: Some(opaque_type_map), + obligations: obligations.into_vec(), + }) + }, + || "input_output".to_string(), + ), + )?; + + let universal_region_relations = match self.universal_region_relations { + Some(rel) => rel, + None => return Ok(()), + }; + + // Finally, if we instantiated the anon types successfully, we + // have to solve any bounds (e.g., `-> impl Iterator` needs to + // prove that `T: Iterator` where `T` is the type we + // instantiated it with). + if let Some(opaque_type_map) = opaque_type_map { + for (opaque_def_id, opaque_decl) in opaque_type_map { + self.fully_perform_op( + locations, + category, + CustomTypeOp::new( + |_cx| { + infcx.constrain_opaque_type( + opaque_def_id, + &opaque_decl, + universal_region_relations + ); + Ok(InferOk { + value: (), + obligations: vec![], + }) + }, + || "opaque_type_map".to_string(), + ), + )?; + } + } + Ok(()) + } + fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx } @@ -942,7 +1072,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let place_ty = place.ty(mir, tcx).to_ty(tcx); let rv_ty = rv.ty(mir, tcx); - if let Err(terr) = self.sub_types( + if let Err(terr) = self.sub_types_or_anon( rv_ty, place_ty, location.to_locations(), @@ -1235,7 +1365,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let locations = term_location.to_locations(); - if let Err(terr) = self.sub_types( + if let Err(terr) = self.sub_types_or_anon( sig.output(), dest_ty, locations, @@ -2104,6 +2234,7 @@ impl MirPass for TypeckMir { &[], None, None, + None, |_| (), ); @@ -2128,3 +2259,21 @@ impl NormalizeLocation for Location { Locations::Single(self) } } + +#[derive(Debug, Default)] +struct ObligationAccumulator<'tcx> { + obligations: PredicateObligations<'tcx>, +} + +impl<'tcx> ObligationAccumulator<'tcx> { + fn add(&mut self, value: InferOk<'tcx, T>) -> T { + let InferOk { value, obligations } = value; + self.obligations.extend(obligations); + value + } + + fn into_vec(self) -> PredicateObligations<'tcx> { + self.obligations + } +} + diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d68899e216c..7265d82935b 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -65,7 +65,7 @@ nodes within the function. The types of top-level items, which never contain unbound type variables, are stored directly into the `tcx` tables. -n.b.: A type variable is not the same thing as a type parameter. A +N.B.: A type variable is not the same thing as a type parameter. A type variable is rather an "instance" of a type parameter: that is, given a generic function `fn foo(t: T)`: while checking the function `foo`, the type `ty_param(0)` refers to the type `T`, which @@ -852,7 +852,7 @@ fn typeck_tables_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_abi(tcx, span, fn_sig.abi()); - // Compute the fty from point of view of inside fn. + // Compute the fty from point of view of inside the fn. let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); let fn_sig = @@ -869,10 +869,20 @@ 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.require_type_is_sized(expected_type, body.value.span, traits::SizedReturnType); + 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); - fcx.check_expr_coercable_to_type(&body.value, expected_type); + fcx.check_expr_coercable_to_type(&body.value, revealed_ty); fcx }; @@ -957,9 +967,14 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for GatherLocalsVisitor<'a, 'gcx, 'tcx> { let o_ty = self.fcx.to_ty(&ty); debug!("visit_local: ty.hir_id={:?} o_ty={:?} c_ty={:?}", ty.hir_id, o_ty, 1); - let revealed_ty = self.fcx.instantiate_opaque_types_from_value( - self.parent_id, - &o_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_response(&revealed_ty); self.fcx.tables.borrow_mut().user_provided_tys_mut().insert(ty.hir_id, c_ty); @@ -1288,90 +1303,96 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, check_packed(tcx, span, def_id); } -pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { - debug!("check_item_type(it.id={}, it.name={})", - it.id, - tcx.item_path_str(tcx.hir.local_def_id(it.id))); +pub fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) { + debug!( + "check_item_type(it.id={}, it.name={})", + it.id, + tcx.item_path_str(tcx.hir.local_def_id(it.id)) + ); let _indenter = indenter(); match it.node { - // Consts can play a role in type-checking, so they are included here. - hir::ItemKind::Static(..) => { - let def_id = tcx.hir.local_def_id(it.id); - tcx.typeck_tables_of(def_id); - maybe_check_static_with_link_section(tcx, def_id, it.span); - } - hir::ItemKind::Const(..) => { - tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); - } - hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, - it.span, - &enum_definition.variants, - it.id); - } - hir::ItemKind::Fn(..) => {} // entirely within check_item_body - hir::ItemKind::Impl(.., ref impl_item_refs) => { - debug!("ItemKind::Impl {} with id {}", it.name, it.id); - let impl_def_id = tcx.hir.local_def_id(it.id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { - check_impl_items_against_trait(tcx, - it.span, - impl_def_id, - impl_trait_ref, - impl_item_refs); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); - } - } - hir::ItemKind::Trait(..) => { - let def_id = tcx.hir.local_def_id(it.id); - check_on_unimplemented(tcx, def_id, it); - } - hir::ItemKind::Struct(..) => { - check_struct(tcx, it.id, it.span); - } - hir::ItemKind::Union(..) => { - check_union(tcx, it.id, it.span); - } - hir::ItemKind::Existential(..) | - hir::ItemKind::Ty(..) => { - let def_id = tcx.hir.local_def_id(it.id); - let pty_ty = tcx.type_of(def_id); - let generics = tcx.generics_of(def_id); - check_bounds_are_used(tcx, &generics, pty_ty); - } - hir::ItemKind::ForeignMod(ref m) => { - check_abi(tcx, it.span, m.abi); + // Consts can play a role in type-checking, so they are included here. + hir::ItemKind::Static(..) => { + let def_id = tcx.hir.local_def_id(it.id); + tcx.typeck_tables_of(def_id); + maybe_check_static_with_link_section(tcx, def_id, it.span); + } + hir::ItemKind::Const(..) => { + tcx.typeck_tables_of(tcx.hir.local_def_id(it.id)); + } + hir::ItemKind::Enum(ref enum_definition, _) => { + check_enum(tcx, it.span, &enum_definition.variants, it.id); + } + hir::ItemKind::Fn(..) => {} // entirely within check_item_body + hir::ItemKind::Impl(.., ref impl_item_refs) => { + debug!("ItemKind::Impl {} with id {}", it.name, it.id); + let impl_def_id = tcx.hir.local_def_id(it.id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait( + tcx, + it.span, + impl_def_id, + impl_trait_ref, + impl_item_refs, + ); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(tcx, trait_def_id, it); + } + } + hir::ItemKind::Trait(..) => { + let def_id = tcx.hir.local_def_id(it.id); + check_on_unimplemented(tcx, def_id, it); + } + hir::ItemKind::Struct(..) => { + check_struct(tcx, it.id, it.span); + } + hir::ItemKind::Union(..) => { + check_union(tcx, it.id, it.span); + } + hir::ItemKind::Existential(..) | hir::ItemKind::Ty(..) => { + let def_id = tcx.hir.local_def_id(it.id); + let pty_ty = tcx.type_of(def_id); + let generics = tcx.generics_of(def_id); + check_bounds_are_used(tcx, &generics, pty_ty); + } + hir::ItemKind::ForeignMod(ref m) => { + check_abi(tcx, it.span, m.abi); - if m.abi == Abi::RustIntrinsic { - for item in &m.items { - intrinsic::check_intrinsic_type(tcx, item); - } - } else if m.abi == Abi::PlatformIntrinsic { - for item in &m.items { - intrinsic::check_platform_intrinsic_type(tcx, item); - } - } else { - for item in &m.items { - let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); - if generics.params.len() - generics.own_counts().lifetimes != 0 { - let mut err = struct_span_err!(tcx.sess, item.span, E0044, - "foreign items may not have type parameters"); - err.span_label(item.span, "can't have type parameters"); - // FIXME: once we start storing spans for type arguments, turn this into a - // suggestion. - err.help("use specialization instead of type parameters by replacing them \ - with concrete types like `u32`"); - err.emit(); + if m.abi == Abi::RustIntrinsic { + for item in &m.items { + intrinsic::check_intrinsic_type(tcx, item); } + } else if m.abi == Abi::PlatformIntrinsic { + for item in &m.items { + intrinsic::check_platform_intrinsic_type(tcx, item); + } + } else { + for item in &m.items { + let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); + if generics.params.len() - generics.own_counts().lifetimes != 0 { + let mut err = struct_span_err!( + tcx.sess, + item.span, + E0044, + "foreign items may not have type parameters" + ); + err.span_label(item.span, "can't have type parameters"); + // FIXME: once we start storing spans for type arguments, turn this into a + // suggestion. + err.help( + "use specialization instead of type parameters by replacing them \ + with concrete types like `u32`", + ); + err.emit(); + } - if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node { - require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span); + if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.node { + require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span); + } } } } - } - _ => {/* nothing to do */ } + _ => { /* nothing to do */ } } } @@ -3936,7 +3957,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> { } hir::ExprKind::Path(ref qpath) => { let (def, opt_ty, segs) = self.resolve_ty_and_def_ufcs(qpath, expr.id, expr.span); - debug!("path_foo: {:?} {:?}", def, opt_ty); let ty = if def != Def::Err { self.instantiate_value_path(segs, opt_ty, def, expr.span, id).0 } else { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 65ffd96e7a0..eb40ea01630 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -494,7 +494,7 @@ declare_features! ( // Allows `Self` in type definitions (active, self_in_typedefs, "1.30.0", Some(49303), None), - // unsized rvalues at arguments and parameters + // Allows unsized rvalues at arguments and parameters (active, unsized_locals, "1.30.0", Some(48055), None), // #![test_runner] @@ -505,13 +505,16 @@ declare_features! ( (active, custom_inner_attributes, "1.30.0", Some(38356), None), // Self struct constructor (RFC 2302) - (active, self_struct_ctor, "1.31.0", Some(51994), None), + (active, self_struct_ctor, "1.30.0", Some(51994), None), // allow mixing of bind-by-move in patterns and references to // those identifiers in guards, *if* we are using MIR-borrowck // (aka NLL). Essentially this means you need to be on // edition:2018 or later. (active, bind_by_move_pattern_guards, "1.30.0", Some(15287), None), + + // Allows `impl Trait` in bindings (`let`, `const`, `static`) + (active, impl_trait_in_bindings, "1.30.0", Some(34511), None), ); declare_features! ( diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs new file mode 100644 index 00000000000..9c76719e26c --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.rs @@ -0,0 +1,17 @@ +// Copyright 2018 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. + +const FOO: impl Copy = 42; + +static BAR: impl Copy = 42; + +fn main() { + let foo = impl Copy = 42; +} diff --git a/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr new file mode 100644 index 00000000000..52c99a7b159 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-impl_trait_in_bindings.stderr @@ -0,0 +1,21 @@ +error: expected expression, found keyword `impl` + --> $DIR/feature-gate-impl_trait_in_bindings.rs:16:15 + | +LL | let foo = impl Copy = 42; + | ^^^^ expected expression + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-impl_trait_in_bindings.rs:11:12 + | +LL | const FOO: impl Copy = 42; + | ^^^^^^^^^ + +error[E0562]: `impl Trait` not allowed outside of function and inherent method return types + --> $DIR/feature-gate-impl_trait_in_bindings.rs:13:13 + | +LL | static BAR: impl Copy = 42; + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0562`. diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs similarity index 100% rename from src/test/ui/feature-gates/feature-gate-self-in-typedefs.rs rename to src/test/ui/feature-gates/feature-gate-self_in_typedefs.rs diff --git a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr similarity index 84% rename from src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr rename to src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr index c3f9abd90a7..22ca92bbe13 100644 --- a/src/test/ui/feature-gates/feature-gate-self-in-typedefs.stderr +++ b/src/test/ui/feature-gates/feature-gate-self_in_typedefs.stderr @@ -1,5 +1,5 @@ error[E0411]: cannot find type `Self` in this scope - --> $DIR/feature-gate-self-in-typedefs.rs:13:17 + --> $DIR/feature-gate-self_in_typedefs.rs:13:17 | LL | Cons(T, &'a Self) | ^^^^ `Self` is only available in traits and impls