Auto merge of #106253 - nbdd0121:upcast, r=compiler-errors
Skip possible where_clause_object_safety lints when checking `multiple_supertrait_upcastable` Fix #106247 To achieve this, I lifted the `WhereClauseReferencesSelf` out from `object_safety_violations` and move it into `is_object_safe` (which is changed to a new query). cc `@dtolnay` r? `@compiler-errors`
This commit is contained in:
commit
d117135f5a
26 changed files with 219 additions and 28 deletions
|
@ -361,7 +361,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> {
|
||||
if self.tcx().is_object_safe(trait_def_id) {
|
||||
if self.tcx().check_is_object_safe(trait_def_id) {
|
||||
self.make_canonical_response(Certainty::Yes)
|
||||
} else {
|
||||
Err(NoSolution)
|
||||
|
|
|
@ -1748,7 +1748,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
|
|||
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
|
||||
predicates
|
||||
.principal_def_id()
|
||||
.map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
|
||||
.map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
|
||||
}
|
||||
// We only want to suggest `impl Trait` to `dyn Trait`s.
|
||||
// For example, `fn foo() -> str` needs to be filtered out.
|
||||
|
|
|
@ -369,7 +369,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
}
|
||||
|
||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||
if !self.selcx.tcx().is_object_safe(trait_def_id) {
|
||||
if !self.selcx.tcx().check_is_object_safe(trait_def_id) {
|
||||
ProcessResult::Error(CodeSelectionError(Unimplemented))
|
||||
} else {
|
||||
ProcessResult::Changed(vec![])
|
||||
|
|
|
@ -62,6 +62,37 @@ fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &'_ [Object
|
|||
)
|
||||
}
|
||||
|
||||
fn check_is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
|
||||
let violations = tcx.object_safety_violations(trait_def_id);
|
||||
|
||||
if violations.is_empty() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the trait contains any other violations, then let the error reporting path
|
||||
// report it instead of emitting a warning here.
|
||||
if violations.iter().all(|violation| {
|
||||
matches!(
|
||||
violation,
|
||||
ObjectSafetyViolation::Method(_, MethodViolationCode::WhereClauseReferencesSelf, _)
|
||||
)
|
||||
}) {
|
||||
for violation in violations {
|
||||
if let ObjectSafetyViolation::Method(
|
||||
_,
|
||||
MethodViolationCode::WhereClauseReferencesSelf,
|
||||
span,
|
||||
) = violation
|
||||
{
|
||||
lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// We say a method is *vtable safe* if it can be invoked on a trait
|
||||
/// object. Note that object-safe traits can have some
|
||||
/// non-vtable-safe methods, so long as they require `Self: Sized` or
|
||||
|
@ -93,19 +124,6 @@ fn object_safety_violations_for_trait(
|
|||
object_safety_violation_for_method(tcx, trait_def_id, &item)
|
||||
.map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
|
||||
})
|
||||
.filter(|violation| {
|
||||
if let ObjectSafetyViolation::Method(
|
||||
_,
|
||||
MethodViolationCode::WhereClauseReferencesSelf,
|
||||
span,
|
||||
) = violation
|
||||
{
|
||||
lint_object_unsafe_trait(tcx, *span, trait_def_id, &violation);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Check the trait itself.
|
||||
|
@ -866,5 +884,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
|
|||
}
|
||||
|
||||
pub fn provide(providers: &mut ty::query::Providers) {
|
||||
*providers = ty::query::Providers { object_safety_violations, ..*providers };
|
||||
*providers =
|
||||
ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
|
||||
}
|
||||
|
|
|
@ -466,7 +466,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
if let Some(principal) = data.principal() {
|
||||
if !self.infcx.tcx.features().object_safe_for_dispatch {
|
||||
principal.with_self_ty(self.tcx(), self_ty)
|
||||
} else if self.tcx().is_object_safe(principal.def_id()) {
|
||||
} else if self.tcx().check_is_object_safe(principal.def_id()) {
|
||||
principal.with_self_ty(self.tcx(), self_ty)
|
||||
} else {
|
||||
return;
|
||||
|
|
|
@ -1009,7 +1009,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
// `T` -> `Trait`
|
||||
(_, &ty::Dynamic(ref data, r, ty::Dyn)) => {
|
||||
let mut object_dids = data.auto_traits().chain(data.principal_def_id());
|
||||
if let Some(did) = object_dids.find(|did| !tcx.is_object_safe(*did)) {
|
||||
if let Some(did) = object_dids.find(|did| !tcx.check_is_object_safe(*did)) {
|
||||
return Err(TraitNotObjectSafe(did));
|
||||
}
|
||||
|
||||
|
|
|
@ -797,7 +797,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
}
|
||||
|
||||
ty::PredicateKind::ObjectSafe(trait_def_id) => {
|
||||
if self.tcx().is_object_safe(trait_def_id) {
|
||||
if self.tcx().check_is_object_safe(trait_def_id) {
|
||||
Ok(EvaluatedToOk)
|
||||
} else {
|
||||
Ok(EvaluatedToErr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue