Skip to content

Commit 58972d1

Browse files
committed
Merge method, type and const object safety checks
1 parent 604ffab commit 58972d1

File tree

2 files changed

+47
-51
lines changed

2 files changed

+47
-51
lines changed

Diff for: compiler/rustc_hir_analysis/src/astconv/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
16431643
}
16441644
}
16451645

1646+
// `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`.
1647+
// So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated
1648+
// types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a
1649+
// corresponding `Projection` clause
16461650
for (projection_bound, _) in &projection_bounds {
16471651
for def_ids in associated_types.values_mut() {
16481652
def_ids.remove(&projection_bound.projection_def_id());

Diff for: compiler/rustc_trait_selection/src/traits/object_safety.rs

+43-51
Original file line numberDiff line numberDiff line change
@@ -115,15 +115,11 @@ fn object_safety_violations_for_trait(
115115
tcx: TyCtxt<'_>,
116116
trait_def_id: DefId,
117117
) -> Vec<ObjectSafetyViolation> {
118-
// Check methods for violations.
118+
// Check assoc items for violations.
119119
let mut violations: Vec<_> = tcx
120120
.associated_items(trait_def_id)
121121
.in_definition_order()
122-
.filter(|item| item.kind == ty::AssocKind::Fn)
123-
.filter_map(|&item| {
124-
object_safety_violation_for_method(tcx, trait_def_id, item)
125-
.map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
126-
})
122+
.filter_map(|&item| object_safety_violation_for_assoc_item(tcx, trait_def_id, item))
127123
.collect();
128124

129125
// Check the trait itself.
@@ -145,30 +141,6 @@ fn object_safety_violations_for_trait(
145141
violations.push(ObjectSafetyViolation::SupertraitNonLifetimeBinder(spans));
146142
}
147143

148-
violations.extend(
149-
tcx.associated_items(trait_def_id)
150-
.in_definition_order()
151-
.filter(|item| item.kind == ty::AssocKind::Const)
152-
.map(|item| {
153-
let ident = item.ident(tcx);
154-
ObjectSafetyViolation::AssocConst(ident.name, ident.span)
155-
}),
156-
);
157-
158-
if !tcx.features().generic_associated_types_extended {
159-
violations.extend(
160-
tcx.associated_items(trait_def_id)
161-
.in_definition_order()
162-
.filter(|item| item.kind == ty::AssocKind::Type)
163-
.filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
164-
.filter(|item| item.opt_rpitit_info.is_none())
165-
.map(|item| {
166-
let ident = item.ident(tcx);
167-
ObjectSafetyViolation::GAT(ident.name, ident.span)
168-
}),
169-
);
170-
}
171-
172144
debug!(
173145
"object_safety_violations_for_trait(trait_def_id={:?}) = {:?}",
174146
trait_def_id, violations
@@ -401,34 +373,54 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
401373
})
402374
}
403375

404-
/// Returns `Some(_)` if this method makes the containing trait not object safe.
405-
fn object_safety_violation_for_method(
376+
/// Returns `Some(_)` if this item makes the containing trait not object safe.
377+
#[instrument(level = "debug", skip(tcx), ret)]
378+
fn object_safety_violation_for_assoc_item(
406379
tcx: TyCtxt<'_>,
407380
trait_def_id: DefId,
408-
method: ty::AssocItem,
409-
) -> Option<(MethodViolationCode, Span)> {
410-
debug!("object_safety_violation_for_method({:?}, {:?})", trait_def_id, method);
411-
// Any method that has a `Self : Sized` requisite is otherwise
381+
item: ty::AssocItem,
382+
) -> Option<ObjectSafetyViolation> {
383+
// Any item that has a `Self : Sized` requisite is otherwise
412384
// exempt from the regulations.
413-
if generics_require_sized_self(tcx, method.def_id) {
385+
if generics_require_sized_self(tcx, item.def_id) {
414386
return None;
415387
}
416388

417-
let violation = virtual_call_violation_for_method(tcx, trait_def_id, method);
418-
// Get an accurate span depending on the violation.
419-
violation.map(|v| {
420-
let node = tcx.hir().get_if_local(method.def_id);
421-
let span = match (&v, node) {
422-
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
423-
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
424-
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
425-
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
426-
node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
389+
match item.kind {
390+
// Associated consts are never object safe, as they can't have `where` bounds yet at all,
391+
// and associated const bounds in trait objects aren't a thing yet either.
392+
ty::AssocKind::Const => {
393+
Some(ObjectSafetyViolation::AssocConst(item.name, item.ident(tcx).span))
394+
}
395+
ty::AssocKind::Fn => virtual_call_violation_for_method(tcx, trait_def_id, item).map(|v| {
396+
let node = tcx.hir().get_if_local(item.def_id);
397+
// Get an accurate span depending on the violation.
398+
let span = match (&v, node) {
399+
(MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
400+
(MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
401+
(MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
402+
(MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
403+
node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
404+
}
405+
_ => item.ident(tcx).span,
406+
};
407+
408+
ObjectSafetyViolation::Method(item.name, v, span)
409+
}),
410+
// Associated types can only be object safe if they have `Self: Sized` bounds.
411+
ty::AssocKind::Type => {
412+
if !tcx.features().generic_associated_types_extended
413+
&& !tcx.generics_of(item.def_id).params.is_empty()
414+
&& item.opt_rpitit_info.is_none()
415+
{
416+
Some(ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span))
417+
} else {
418+
// We will permit associated types if they are explicitly mentioned in the trait object.
419+
// We can't check this here, as here we only check if it is guaranteed to not be possible.
420+
None
427421
}
428-
_ => method.ident(tcx).span,
429-
};
430-
(v, span)
431-
})
422+
}
423+
}
432424
}
433425

434426
/// Returns `Some(_)` if this method cannot be called on a trait

0 commit comments

Comments
 (0)