Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
Bryanskiy committed Feb 6, 2024
1 parent ea37e80 commit df3a6ab
Show file tree
Hide file tree
Showing 32 changed files with 470 additions and 108 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ declare_features! (
(internal, compiler_builtins, "1.13.0", None),
/// Allows writing custom MIR
(internal, custom_mir, "1.65.0", None),
/// Allows using bunch of default auto traits
(unstable, default_auto_traits, "CURRENT_RUSTC_VERSION", None),
/// Outputs useful `assert!` messages
(unstable, generic_assert, "1.63.0", None),
/// Allows using the `rust-intrinsic`'s "ABI".
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ impl LanguageItems {
.enumerate()
.filter_map(|(i, id)| id.map(|id| (LangItem::from_u32(i as u32).unwrap(), id)))
}

pub fn is_default_trait(&self, def_id: DefId) -> bool {
DEFAULT_TRAITS
.iter()
.find(|&&default_trait| self.get(default_trait) == Some(def_id))
.is_some()
}
}

// The actual lang items defined come at the end of this file in one handy table.
Expand Down Expand Up @@ -139,6 +146,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {

language_item_table! {
// Variant name, Name, Getter method name, Target Generic requirements;
SyncDrop, sym::sync_drop, sync_drop_trait, Target::Trait, GenericRequirement::None;
Leak, sym::leak, leak_trait, Target::Trait, GenericRequirement::None;
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
Expand Down Expand Up @@ -349,6 +358,9 @@ pub enum GenericRequirement {
Exact(usize),
}

pub static DEFAULT_TRAITS: &'static [LangItem] =
&[LangItem::Sized, LangItem::Leak, LangItem::SyncDrop];

pub static FN_TRAITS: &'static [LangItem] = &[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];

pub static OPERATORS: &'static [LangItem] = &[
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_hir/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ macro_rules! weak_lang_items {
}

weak_lang_items! {
SyncDrop, sync_drop;
Leak, leak;
PanicImpl, rust_begin_unwind;
EhPersonality, rust_eh_personality;
EhCatchTypeinfo, rust_eh_catch_typeinfo;
Expand Down
108 changes: 69 additions & 39 deletions compiler/rustc_hir_analysis/src/astconv/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,60 @@ use crate::bounds::Bounds;
use crate::errors;

impl<'tcx> dyn AstConv<'tcx> + '_ {
/// Sets `implicitly_sized` to true on `Bounds` if necessary
pub(crate) fn add_implicitly_sized(
/// Sets Sized or default_auto_traits to true on `Bounds` if necessary
pub(crate) fn add_implicit_traits(
&self,
bounds: &mut Bounds<'tcx>,
self_ty: Ty<'tcx>,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
span: Span,
) {
hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| {
self.add_implicit_trait(
*default_trait,
bounds,
self_ty,
ast_bounds,
self_ty_where_predicates,
span,
);
});
}

pub(crate) fn add_implicit_trait(
&self,
trait_: hir::LangItem,
bounds: &mut Bounds<'tcx>,
self_ty: Ty<'tcx>,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
span: Span,
) {
let tcx = self.tcx();
let sized_def_id = tcx.lang_items().sized_trait();
let mut seen_negative_sized_bound = false;
let mut seen_positive_sized_bound = false;
let trait_id = tcx.lang_items().get(trait_);

if self.check_for_implicit_trait(trait_id, ast_bounds, self_ty_where_predicates)
&& (trait_ == hir::LangItem::Sized || tcx.features().default_auto_traits)
{
// There was no `?Trait` or `!Trait` bound;
// add `Trait` if it's available.
bounds.push_lang_item_trait(tcx, self_ty, trait_, span);
}
}

fn check_for_implicit_trait(
&self,
trait_def_id: Option<DefId>,
ast_bounds: &'tcx [hir::GenericBound<'tcx>],
self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
) -> bool {
let Some(trait_def_id) = trait_def_id else {
return false;
};
let tcx = self.tcx();
let mut seen_negative_bound = false;
let mut seen_positive_bound = false;

// Try to find an unbound in bounds.
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
Expand All @@ -40,17 +81,13 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
match modifier {
hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
hir::TraitBoundModifier::Negative => {
if let Some(sized_def_id) = sized_def_id
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_negative_sized_bound = true;
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
seen_negative_bound = true;
}
}
hir::TraitBoundModifier::None => {
if let Some(sized_def_id) = sized_def_id
&& ptr.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_positive_sized_bound = true;
if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
seen_positive_bound = true;
}
}
_ => {}
Expand All @@ -68,36 +105,29 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
}
}

if unbounds.len() > 1 {
tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
spans: unbounds.iter().map(|ptr| ptr.span).collect(),
});
}

let mut seen_sized_unbound = false;
let mut seen_unbound = false;
for unbound in unbounds {
if let Some(sized_def_id) = sized_def_id
&& unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id)
{
seen_sized_unbound = true;
continue;
let unbound_def_id = unbound.trait_ref.trait_def_id();
if unbound_def_id == Some(trait_def_id) {
seen_unbound = true;
}
// There was a `?Trait` bound, but it was not `?Sized`; warn.
tcx.dcx().span_warn(
unbound.span,
"relaxing a default bound only does something for `?Sized`; \
all other traits are not bound by default",
);
}

if seen_sized_unbound || seen_negative_sized_bound || seen_positive_sized_bound {
// There was in fact a `?Sized`, `!Sized` or explicit `Sized` bound;
// we don't need to do anything.
} else if sized_def_id.is_some() {
// There was no `?Sized`, `!Sized` or explicit `Sized` bound;
// add `Sized` if it's available.
bounds.push_sized(tcx, self_ty, span);
let emit_relax_err = || {
tcx.dcx().span_warn(
unbound.span,
"relaxing a default bound only does something for `?Sized` and `default_auto_traits`; \
all other traits are not bound by default",
);
};

match unbound_def_id {
Some(def_id) if !tcx.lang_items().is_default_trait(def_id) => emit_relax_err(),
None => emit_relax_err(),
_ => {}
}
}

!(seen_unbound || seen_negative_bound || seen_positive_bound)
}

/// This helper takes a *converted* parameter type (`param_ty`)
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_hir_analysis/src/astconv/object_safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
potential_assoc_types.extend(cur_potential_assoc_types);
}
}
// FIXME: support polarity for trait objects
if tcx.features().default_auto_traits {
hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| {
if *default_trait != hir::LangItem::Sized {
bounds.push_lang_item_trait(tcx, dummy_self, *default_trait, span);
}
});
}

let mut trait_bounds = vec![];
let mut projection_bounds = vec![];
Expand Down
23 changes: 18 additions & 5 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,24 @@ 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);
let Some(trait_def_id) = tcx.lang_items().get(lang_item) else {
return;
};
let trait_ref = ty::TraitRef::new(tcx, trait_def_id, [ty]);
if lang_item == LangItem::Sized {
// 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 {
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 @@ -316,8 +316,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.lang_items().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
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn associated_type_bounds<'tcx>(
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
icx.astconv().add_implicit_traits(&mut bounds, item_ty, ast_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 @@ -68,7 +68,7 @@ fn opaque_type_bounds<'tcx>(
let icx = ItemCtxt::new(tcx, opaque_def_id);
let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, PredicateFilter::All);
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
icx.astconv().add_implicit_traits(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);

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

ItemKind::Trait(_, _, generics, self_bounds, ..)
| ItemKind::TraitAlias(generics, self_bounds) => {
is_trait = Some(self_bounds);
is_trait = Some((self_bounds, item.span));
generics
}
ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
Expand All @@ -169,11 +169,27 @@ 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.astconv()
.compute_bounds(tcx.types.self_param, self_bounds, PredicateFilter::All)
.clauses(),
);
let mut bounds =
icx.astconv().compute_bounds(tcx.types.self_param, self_bounds.0, PredicateFilter::All);

let sized_trait = tcx.lang_items().sized_trait();
let trait_def_id = def_id.to_def_id();
hir::lang_items::DEFAULT_TRAITS.iter().for_each(|default_trait| {
if *default_trait != hir::LangItem::Sized
&& (Some(trait_def_id) == sized_trait
|| !tcx.lang_items().is_default_trait(def_id.to_def_id()))
{
icx.astconv().add_implicit_trait(
*default_trait,
&mut bounds,
tcx.types.self_param,
self_bounds.0,
None,
self_bounds.1,
);
}
});
predicates.extend(bounds.clauses());
}

// In default impls, we can assume that the self type implements
Expand All @@ -199,7 +215,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
let param_ty = icx.astconv().hir_id_to_bound_ty(param.hir_id);
let mut bounds = Bounds::default();
// Params are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(
icx.astconv().add_implicit_traits(
&mut bounds,
param_ty,
&[],
Expand Down
Loading

0 comments on commit df3a6ab

Please sign in to comment.