diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index ee18968ff35..5aac23f0f5f 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -71,7 +71,8 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> { fn item_ty_level(&self, item_def_id: DefId) -> Option { let ty_def_id = match self.tcx.item_type(item_def_id).sty { ty::TyAdt(adt, _) => adt.did, - ty::TyTrait(ref obj) => obj.principal.def_id(), + ty::TyDynamic(ref obj, ..) if obj.principal().is_some() => + obj.principal().unwrap().def_id(), ty::TyProjection(ref proj) => proj.trait_ref.def_id, _ => return Some(AccessLevel::Public) }; @@ -359,7 +360,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let ty_def_id = match ty.sty { ty::TyAdt(adt, _) => Some(adt.did), - ty::TyTrait(ref obj) => Some(obj.principal.def_id()), + ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id), ty::TyFnDef(def_id, ..) | ty::TyAnon(def_id, _) => Some(def_id), @@ -934,7 +935,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<' fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let ty_def_id = match ty.sty { ty::TyAdt(adt, _) => Some(adt.did), - ty::TyTrait(ref obj) => Some(obj.principal.def_id()), + ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()), ty::TyProjection(ref proj) => { if self.required_visibility == ty::Visibility::PrivateExternal { // Conservatively approximate the whole type alias as public without diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 986d817a10c..9f3887a8768 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -962,7 +962,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ty.id, path.segments.last().unwrap(), span, - partition_bounds(tcx, span, bounds)) + partition_bounds(bounds)) } else { struct_span_err!(tcx.sess, ty.span, E0172, "expected a reference to a trait") @@ -1045,11 +1045,12 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { trait_segment, &mut projection_bounds); - let PartitionedBounds { auto_traits, - trait_bounds, + let PartitionedBounds { trait_bounds, region_bounds } = partitioned_bounds; + let (auto_traits, trait_bounds) = split_auto_traits(tcx, trait_bounds); + if !trait_bounds.is_empty() { let b = &trait_bounds[0]; let span = b.trait_ref.path.span; @@ -1443,7 +1444,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { path_id, path.segments.last().unwrap(), span, - partition_bounds(tcx, span, &[])) + partition_bounds(&[])) } Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => { assert_eq!(opt_self_ty, None); @@ -1897,7 +1898,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { ast_bounds: &[hir::TyParamBound]) -> Ty<'tcx> { - let mut partitioned_bounds = partition_bounds(self.tcx(), span, &ast_bounds[..]); + let mut partitioned_bounds = partition_bounds(ast_bounds); let trait_bound = if !partitioned_bounds.trait_bounds.is_empty() { partitioned_bounds.trait_bounds.remove(0) @@ -1982,49 +1983,62 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o { } pub struct PartitionedBounds<'a> { - pub auto_traits: Vec, pub trait_bounds: Vec<&'a hir::PolyTraitRef>, pub region_bounds: Vec<&'a hir::Lifetime>, } -/// Divides a list of bounds from the AST into three groups: builtin bounds (Copy, Sized etc), -/// general trait bounds, and region bounds. -pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, - _span: Span, - ast_bounds: &'b [hir::TyParamBound]) - -> PartitionedBounds<'b> +/// Divides a list of general trait bounds into two groups: builtin bounds (Sync/Send) and the +/// remaining general trait bounds. +fn split_auto_traits<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_bounds: Vec<&'b hir::PolyTraitRef>) + -> (Vec, Vec<&'b hir::PolyTraitRef>) +{ + let (auto_traits, trait_bounds): (Vec<_>, _) = trait_bounds.into_iter().partition(|bound| { + match bound.trait_ref.path.def { + Def::Trait(trait_did) => { + // Checks whether `trait_did` refers to one of the builtin + // traits, like `Send`, and adds it to `auto_traits` if so. + if Some(trait_did) == tcx.lang_items.send_trait() || + Some(trait_did) == tcx.lang_items.sync_trait() { + let segments = &bound.trait_ref.path.segments; + let parameters = &segments[segments.len() - 1].parameters; + if !parameters.types().is_empty() { + check_type_argument_count(tcx, bound.trait_ref.path.span, + parameters.types().len(), &[]); + } + if !parameters.lifetimes().is_empty() { + report_lifetime_number_error(tcx, bound.trait_ref.path.span, + parameters.lifetimes().len(), 0); + } + true + } else { + false + } + } + _ => false + } + }); + + let auto_traits = auto_traits.into_iter().map(|tr| { + if let Def::Trait(trait_did) = tr.trait_ref.path.def { + trait_did + } else { + unreachable!() + } + }).collect::>(); + + (auto_traits, trait_bounds) +} + +/// Divides a list of bounds from the AST into two groups: general trait bounds and region bounds +pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(ast_bounds: &'b [hir::TyParamBound]) + -> PartitionedBounds<'b> { - let mut auto_traits = Vec::new(); let mut region_bounds = Vec::new(); let mut trait_bounds = Vec::new(); for ast_bound in ast_bounds { match *ast_bound { hir::TraitTyParamBound(ref b, hir::TraitBoundModifier::None) => { - match b.trait_ref.path.def { - Def::Trait(trait_did) => { - // Checks whether `trait_did` refers to one of the builtin - // traits, like `Send`, and adds it to `auto_traits` if so. - if Some(trait_did) == tcx.lang_items.send_trait() || - Some(trait_did) == tcx.lang_items.sync_trait() { - auto_traits.push(trait_did); - let segments = &b.trait_ref.path.segments; - let parameters = &segments[segments.len() - 1].parameters; - if !parameters.types().is_empty() { - check_type_argument_count(tcx, b.trait_ref.path.span, - parameters.types().len(), &[]); - } - if !parameters.lifetimes().is_empty() { - report_lifetime_number_error(tcx, b.trait_ref.path.span, - parameters.lifetimes().len(), 0); - } - continue; // success - } - } - _ => { - // Not a trait? that's an error, but it'll get - // reported later. - } - } trait_bounds.push(b); } hir::TraitTyParamBound(_, hir::TraitBoundModifier::Maybe) => {} @@ -2035,7 +2049,6 @@ pub fn partition_bounds<'a, 'b, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, } PartitionedBounds { - auto_traits: auto_traits, trait_bounds: trait_bounds, region_bounds: region_bounds, } @@ -2110,7 +2123,7 @@ fn report_lifetime_number_error(tcx: TyCtxt, span: Span, number: usize, expected #[derive(PartialEq, Eq, Clone, Debug)] pub struct Bounds<'tcx> { pub region_bounds: Vec<&'tcx ty::Region>, - pub auto_traits: Vec, + pub implicitly_sized: bool, pub trait_bounds: Vec>, pub projection_bounds: Vec>, } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 2b69ac12a2c..8495c1b3fb8 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -1584,11 +1584,10 @@ fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, assert!(prev_predicates.is_none()); } -// Add the Sized bound, unless the type parameter is marked as `?Sized`. -fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, - bounds: &mut Vec, - ast_bounds: &[hir::TyParamBound], - span: Span) +// Is it marked with ?Sized +fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, + ast_bounds: &[hir::TyParamBound], + span: Span) -> bool { let tcx = astconv.tcx(); @@ -1621,11 +1620,13 @@ fn add_unsized_bound<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, } } _ if kind_id.is_ok() => { - bounds.push(kind_id.unwrap()); + return false; } // No lang item for Sized, so we can't add it as a bound. None => {} } + + true } /// Returns the early-bound lifetimes declared in this generics @@ -1907,14 +1908,9 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, { let tcx = astconv.tcx(); let PartitionedBounds { - mut auto_traits, trait_bounds, region_bounds - } = partition_bounds(tcx, span, &ast_bounds); - - if let SizedByDefault::Yes = sized_by_default { - add_unsized_bound(astconv, &mut auto_traits, ast_bounds, span); - } + } = partition_bounds(&ast_bounds); let mut projection_bounds = vec![]; @@ -1932,9 +1928,15 @@ pub fn compute_bounds<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>, trait_bounds.sort_by(|a,b| a.def_id().cmp(&b.def_id())); + let implicitly_sized = if let SizedByDefault::Yes = sized_by_default { + !is_unsized(astconv, ast_bounds, span) + } else { + false + }; + Bounds { region_bounds: region_bounds, - auto_traits: auto_traits, + implicitly_sized: implicitly_sized, trait_bounds: trait_bounds, projection_bounds: projection_bounds, } diff --git a/src/test/compile-fail/issue-16966.rs b/src/test/compile-fail/issue-16966.rs index 5dbf7546de2..508442fcb94 100644 --- a/src/test/compile-fail/issue-16966.rs +++ b/src/test/compile-fail/issue-16966.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:type annotations required +// error-pattern:type annotations or generic parameter binding required fn main() { panic!( std::default::Default::default()