Skip to content

Commit

Permalink
initial implementation for default auto traits
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed Apr 25, 2024
1 parent 31e6e8c commit 2500778
Show file tree
Hide file tree
Showing 61 changed files with 1,218 additions and 202 deletions.
10 changes: 8 additions & 2 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1465,8 +1465,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
continue;
}
let is_param = *is_param.get_or_insert_with(compute_is_param);
if !is_param {
self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() });
if !is_param && !self.tcx.features().more_maybe_bounds {
self.tcx
.sess
.create_feature_err(
MisplacedRelaxTraitBound { span: bound.span() },
sym::more_maybe_bounds,
)
.emit();
}
}
}
Expand Down
28 changes: 13 additions & 15 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx,
TraitBoundModifiers::NONE,
);
let bound = (bound, hir::TraitBoundModifier::None);
let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound)
Expand Down Expand Up @@ -1369,21 +1370,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// We can safely ignore constness here since AST validation
// takes care of rejecting invalid modifier combinations and
// const trait bounds in trait object types.
GenericBound::Trait(ty, modifiers) => match modifiers.polarity {
BoundPolarity::Positive | BoundPolarity::Negative(_) => {
Some(this.lower_poly_trait_ref(
ty,
itctx,
// Still, don't pass along the constness here; we don't want to
// synthesize any host effect args, it'd only cause problems.
TraitBoundModifiers {
constness: BoundConstness::Never,
..*modifiers
},
))
}
BoundPolarity::Maybe(_) => None,
},
GenericBound::Trait(ty, modifiers) => {
// Still, don't pass along the constness here; we don't want to
// synthesize any host effect args, it'd only cause problems.
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
..*modifiers
};
let trait_ref = this.lower_poly_trait_ref(ty, itctx, modifiers);
let polarity = this.lower_trait_bound_modifiers(modifiers);
Some((trait_ref, polarity))
}
GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() {
lifetime_bound = Some(this.lower_lifetime(lifetime));
Expand Down Expand Up @@ -2543,6 +2540,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span),
};
let principal = (principal, hir::TraitBoundModifier::None);

// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
Expand Down
28 changes: 21 additions & 7 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1289,14 +1289,28 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
fn visit_param_bound(&mut self, bound: &'a GenericBound, ctxt: BoundKind) {
if let GenericBound::Trait(poly, modifiers) = bound {
match (ctxt, modifiers.constness, modifiers.polarity) {
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path),
});
(BoundKind::SuperTraits, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds =>
{
self.session
.create_feature_err(
errors::OptionalTraitSupertrait {
span: poly.span,
path_str: pprust::path_to_string(&poly.trait_ref.path),
},
sym::more_maybe_bounds,
)
.emit();
}
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_)) => {
self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
(BoundKind::TraitObject, BoundConstness::Never, BoundPolarity::Maybe(_))
if !self.features.more_maybe_bounds =>
{
self.session
.create_feature_err(
errors::OptionalTraitObject { span: poly.span },
sym::more_maybe_bounds,
)
.emit();
}
(BoundKind::TraitObject, BoundConstness::Always(_), BoundPolarity::Positive) => {
self.dcx().emit_err(errors::ConstBoundTraitObject { span: poly.span });
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,8 @@ declare_features! (
(unstable, lifetime_capture_rules_2024, "1.76.0", None),
/// Allows `#[link(..., cfg(..))]`; perma-unstable per #37406
(unstable, link_cfg, "1.14.0", None),
/// Allows using `?Trait` trait bounds in more contexts.
(internal, more_maybe_bounds, "CURRENT_RUSTC_VERSION", None),
/// Allows the `multiple_supertrait_upcastable` lint.
(unstable, multiple_supertrait_upcastable, "1.69.0", None),
/// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2673,7 +2673,11 @@ pub enum TyKind<'hir> {
OpaqueDef(ItemId, &'hir [GenericArg<'hir>], bool),
/// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime.
TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
TraitObject(
&'hir [(PolyTraitRef<'hir>, TraitBoundModifier)],
&'hir Lifetime,
TraitObjectSyntax,
),
/// Unused for now.
Typeof(AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_hir/src/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -887,7 +887,9 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
try_visit!(visitor.visit_array_length(length));
}
TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
walk_list!(visitor, visit_poly_trait_ref, bounds);
for (bound, _modifier) in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound));
}
try_visit!(visitor.visit_lifetime(lifetime));
}
TyKind::Typeof(ref expression) => try_visit!(visitor.visit_anon_const(expression)),
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,12 @@ language_item_table! {

String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;

// Experimental lang items for `MCP: Low level components for async drop`(https://github.com/rust-lang/compiler-team/issues/727)
DefaultTrait4, sym::default_trait4, default_trait4_trait, Target::Trait, GenericRequirement::None;
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
}

pub enum GenericRequirement {
Expand Down
26 changes: 21 additions & 5 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,27 @@ impl<'tcx> Bounds<'tcx> {
));
}

pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
pub fn push_lang_item_trait(
&mut self,
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
lang_item: LangItem,
span: Span,
) {
assert_eq!(lang_item.target(), rustc_hir::Target::Trait);
if lang_item == LangItem::Sized {
let sized_trait = tcx.require_lang_item(lang_item, Some(span));
let trait_ref = ty::TraitRef::new(tcx, sized_trait, [ty]);
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
} else {
// Do not generate default bounds if lang item was not defined
let Some(trait_def_id) = tcx.lang_items().get(lang_item) else {
return;
};
let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);
self.clauses.push((trait_ref.to_predicate(tcx), span));
}
}

pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,8 @@ fn bounds_from_generic_predicates<'tcx>(
ty::ClauseKind::Trait(trait_predicate) => {
let entry = types.entry(trait_predicate.self_ty()).or_default();
let def_id = trait_predicate.def_id();
if Some(def_id) != tcx.lang_items().sized_trait() {
// Type params are `Sized` by default, do not add that restriction to the list
if !tcx.is_default_trait(def_id) {
// Do not add that restriction to the list
// if it is a positive requirement.
entry.push(trait_predicate.def_id());
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -849,7 +849,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {

fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind {
hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments {
[s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false,
},
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ fn associated_type_bounds<'tcx>(

let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
// Implicit bounds are added to associated types unless a `?Trait` bound is found
icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span);

let trait_def_id = tcx.local_parent(assoc_item_def_id);
let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id);
Expand Down Expand Up @@ -70,8 +70,8 @@ fn opaque_type_bounds<'tcx>(
ty::print::with_reduced_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.lowerer().lower_mono_bounds(item_ty, hir_bounds, filter);
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.lowerer().add_sized_bound(&mut bounds, item_ty, hir_bounds, None, span);
// Implicit bounds are added to opaque types unless a `?Trait` bound is found
icx.lowerer().add_implicit_traits(&mut bounds, item_ty, hir_bounds, None, span);
debug!(?bounds);

tcx.arena.alloc_from_iter(bounds.clauses())
Expand Down
50 changes: 42 additions & 8 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,30 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}

ItemKind::Trait(_, _, _, self_bounds, ..) | ItemKind::TraitAlias(_, self_bounds) => {
is_trait = Some(self_bounds);
is_trait = Some((self_bounds, item.span));
}
_ => {}
}
};
if let Node::TraitItem(item) = node {
// Implicitly add `Self: Trait` clauses on trait associated items.
// See `add_implicit_super_traits` doc for more details.
let parent = tcx.local_parent(item.hir_id().owner.def_id);
// FIXME(experimental_default_bounds): default bounds on `Pointee::Metadata` causes a normalization fail
if Some(parent.to_def_id()) != tcx.lang_items().pointee_trait() {
let mut bounds = Bounds::default();
let self_ty_where_predicates = (parent, item.generics.predicates);
icx.lowerer().add_implicit_traits_with_filter(
&mut bounds,
tcx.types.self_param,
&[],
Some(self_ty_where_predicates),
item.span,
|tr| tr != hir::LangItem::Sized,
);
predicates.extend(bounds.clauses());
}
}

let generics = tcx.generics_of(def_id);

Expand All @@ -148,11 +167,19 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// on a trait we must also consider the bounds that follow the trait's name,
// like `trait Foo: A + B + C`.
if let Some(self_bounds) = is_trait {
predicates.extend(
icx.lowerer()
.lower_mono_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
let mut bounds = icx.lowerer().lower_mono_bounds(
tcx.types.self_param,
self_bounds.0,
PredicateFilter::All,
);
icx.lowerer().add_implicit_super_traits(
def_id,
&mut bounds,
self_bounds.0,
hir_generics,
self_bounds.1,
);
predicates.extend(bounds.clauses());
}

// In default impls, we can assume that the self type implements
Expand All @@ -177,8 +204,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
GenericParamKind::Type { .. } => {
let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
let mut bounds = Bounds::default();
// Params are implicitly sized unless a `?Sized` bound is found
icx.lowerer().add_sized_bound(
// Implicit bounds are added to type params unless a `?Trait` bound is found
icx.lowerer().add_implicit_traits(
&mut bounds,
param_ty,
&[],
Expand Down Expand Up @@ -601,7 +628,14 @@ pub(super) fn implied_predicates_with_filter(
let icx = ItemCtxt::new(tcx, trait_def_id);

let self_param_ty = tcx.types.self_param;
let superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter);
let mut superbounds = icx.lowerer().lower_mono_bounds(self_param_ty, bounds, filter);
icx.lowerer().add_implicit_super_traits(
trait_def_id,
&mut superbounds,
bounds,
generics,
item.span,
);

let where_bounds_that_match = icx.probe_ty_param_bounds_in_generics(
generics,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| {
for bound in bounds {
for (bound, _) in bounds {
this.visit_poly_trait_ref_inner(
bound,
NonLifetimeBinderAllowed::Deny("trait object types"),
Expand Down
Loading

0 comments on commit 2500778

Please sign in to comment.