Remove unnecessary layout assertions for object-safe receivers
This commit is contained in:
parent
f2c4ccd852
commit
0b26dc0b51
6 changed files with 42 additions and 173 deletions
|
@ -4,19 +4,16 @@
|
||||||
//!
|
//!
|
||||||
//! [^1]: Formerly known as "object safety".
|
//! [^1]: Formerly known as "object safety".
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
|
||||||
use rustc_abi::BackendRepr;
|
|
||||||
use rustc_errors::FatalError;
|
use rustc_errors::FatalError;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_middle::bug;
|
use rustc_middle::bug;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
|
self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
|
||||||
TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
|
TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
|
||||||
TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
|
|
||||||
};
|
};
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_type_ir::elaborate;
|
use rustc_type_ir::elaborate;
|
||||||
|
@ -109,14 +106,6 @@ fn dyn_compatibility_violations_for_trait(
|
||||||
violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
|
violations.push(DynCompatibilityViolation::SupertraitNonLifetimeBinder(spans));
|
||||||
}
|
}
|
||||||
|
|
||||||
if violations.is_empty() {
|
|
||||||
for item in tcx.associated_items(trait_def_id).in_definition_order() {
|
|
||||||
if let ty::AssocKind::Fn = item.kind {
|
|
||||||
check_receiver_correct(tcx, trait_def_id, *item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
violations
|
violations
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,55 +488,6 @@ fn virtual_call_violations_for_method<'tcx>(
|
||||||
errors
|
errors
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This code checks that `receiver_is_dispatchable` is correctly implemented.
|
|
||||||
///
|
|
||||||
/// This check is outlined from the dyn-compatibility check to avoid cycles with
|
|
||||||
/// layout computation, which relies on knowing whether methods are dyn-compatible.
|
|
||||||
fn check_receiver_correct<'tcx>(tcx: TyCtxt<'tcx>, trait_def_id: DefId, method: ty::AssocItem) {
|
|
||||||
if !is_vtable_safe_method(tcx, trait_def_id, method) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let method_def_id = method.def_id;
|
|
||||||
let sig = tcx.fn_sig(method_def_id).instantiate_identity();
|
|
||||||
let typing_env = ty::TypingEnv::non_body_analysis(tcx, method_def_id);
|
|
||||||
let receiver_ty = tcx.liberate_late_bound_regions(method_def_id, sig.input(0));
|
|
||||||
|
|
||||||
if receiver_ty == tcx.types.self_param {
|
|
||||||
// Assumed OK, may change later if unsized_locals permits `self: Self` as dispatchable.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// e.g., `Rc<()>`
|
|
||||||
let unit_receiver_ty = receiver_for_self_ty(tcx, receiver_ty, tcx.types.unit, method_def_id);
|
|
||||||
match tcx.layout_of(typing_env.as_query_input(unit_receiver_ty)).map(|l| l.backend_repr) {
|
|
||||||
Ok(BackendRepr::Scalar(..)) => (),
|
|
||||||
abi => {
|
|
||||||
tcx.dcx().span_delayed_bug(
|
|
||||||
tcx.def_span(method_def_id),
|
|
||||||
format!("receiver {unit_receiver_ty:?} when `Self = ()` should have a Scalar ABI; found {abi:?}"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let trait_object_ty = object_ty_for_trait(tcx, trait_def_id, tcx.lifetimes.re_static);
|
|
||||||
|
|
||||||
// e.g., `Rc<dyn Trait>`
|
|
||||||
let trait_object_receiver =
|
|
||||||
receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method_def_id);
|
|
||||||
match tcx.layout_of(typing_env.as_query_input(trait_object_receiver)).map(|l| l.backend_repr) {
|
|
||||||
Ok(BackendRepr::ScalarPair(..)) => (),
|
|
||||||
abi => {
|
|
||||||
tcx.dcx().span_delayed_bug(
|
|
||||||
tcx.def_span(method_def_id),
|
|
||||||
format!(
|
|
||||||
"receiver {trait_object_receiver:?} when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
|
/// Performs a type instantiation to produce the version of `receiver_ty` when `Self = self_ty`.
|
||||||
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
|
/// For example, for `receiver_ty = Rc<Self>` and `self_ty = Foo`, returns `Rc<Foo>`.
|
||||||
fn receiver_for_self_ty<'tcx>(
|
fn receiver_for_self_ty<'tcx>(
|
||||||
|
@ -569,49 +509,6 @@ fn receiver_for_self_ty<'tcx>(
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates the object type for the current trait. For example,
|
|
||||||
/// if the current trait is `Deref`, then this will be
|
|
||||||
/// `dyn Deref<Target = Self::Target> + 'static`.
|
|
||||||
#[instrument(level = "trace", skip(tcx), ret)]
|
|
||||||
fn object_ty_for_trait<'tcx>(
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
trait_def_id: DefId,
|
|
||||||
lifetime: ty::Region<'tcx>,
|
|
||||||
) -> Ty<'tcx> {
|
|
||||||
let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
|
|
||||||
debug!(?trait_ref);
|
|
||||||
|
|
||||||
let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
|
|
||||||
ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
|
|
||||||
));
|
|
||||||
debug!(?trait_predicate);
|
|
||||||
|
|
||||||
let pred: ty::Predicate<'tcx> = trait_ref.upcast(tcx);
|
|
||||||
let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred])
|
|
||||||
.filter_map(|pred| {
|
|
||||||
debug!(?pred);
|
|
||||||
let pred = pred.as_projection_clause()?;
|
|
||||||
Some(pred.map_bound(|p| {
|
|
||||||
ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
|
|
||||||
tcx, p,
|
|
||||||
))
|
|
||||||
}))
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
// NOTE: Since #37965, the existential predicates list has depended on the
|
|
||||||
// list of predicates to be sorted. This is mostly to enforce that the primary
|
|
||||||
// predicate comes first.
|
|
||||||
elaborated_predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder()));
|
|
||||||
elaborated_predicates.dedup();
|
|
||||||
|
|
||||||
let existential_predicates = tcx.mk_poly_existential_predicates_from_iter(
|
|
||||||
iter::once(trait_predicate).chain(elaborated_predicates),
|
|
||||||
);
|
|
||||||
debug!(?existential_predicates);
|
|
||||||
|
|
||||||
Ty::new_dynamic(tcx, existential_predicates, lifetime, ty::Dyn)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
|
/// Checks the method's receiver (the `self` argument) can be dispatched on when `Self` is a
|
||||||
/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
|
/// trait object. We require that `DispatchableFromDyn` be implemented for the receiver type
|
||||||
/// in the following way:
|
/// in the following way:
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
//@ known-bug: rust-lang/rust#125810
|
|
||||||
#![feature(arbitrary_self_types, dispatch_from_dyn)]
|
|
||||||
|
|
||||||
use std::ops::{Deref, DispatchFromDyn};
|
|
||||||
|
|
||||||
trait Trait<T: Deref<Target = Self> + DispatchFromDyn<T>> {
|
|
||||||
fn MONO_BUF(self: T) -> dyn Trait<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,57 +0,0 @@
|
||||||
//@ known-bug: #90110
|
|
||||||
|
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufReader, BufRead};
|
|
||||||
use std::str::Split;
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
pub trait Parser<D>
|
|
||||||
where dyn Parser<D>: Sized
|
|
||||||
{
|
|
||||||
fn new(split_header: Split<&str>) -> Self where Self: Sized;
|
|
||||||
fn parse_line(&self, split_line: &Split<&str>) -> D;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct CsvReader<D> {
|
|
||||||
parser: Box<dyn Parser<D>>,
|
|
||||||
|
|
||||||
reader: BufReader<File>,
|
|
||||||
buf: String, // Buffer we will read into. Avoids re-allocation on each line.
|
|
||||||
path: String, // Record this so we can return more informative error messages.
|
|
||||||
line: usize, // Same motivation for this.
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<D> CsvReader<D>
|
|
||||||
where dyn Parser<D>: Sized
|
|
||||||
{
|
|
||||||
fn new<F>(path: &str, make_parser: F) -> CsvReader<D>
|
|
||||||
where F: Fn(Split<char>) -> dyn Parser<D> {
|
|
||||||
let file = match File::open(Path::new(path)) {
|
|
||||||
Err(err) => panic!("Couldn't read {}: {}", path, err),
|
|
||||||
Ok(file) => file,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut reader = BufReader::new(file);
|
|
||||||
|
|
||||||
let mut buf = String::new();
|
|
||||||
|
|
||||||
let parser = Box::new(match reader.read_line(&mut buf) {
|
|
||||||
Err(err) => panic!("Failed to read the header line from {}: {}", path, err),
|
|
||||||
Ok(_) => {
|
|
||||||
let split_header = buf.split(',');
|
|
||||||
make_parser(split_header)
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
CsvReader {
|
|
||||||
parser: parser,
|
|
||||||
reader,
|
|
||||||
buf,
|
|
||||||
path: path.to_string(),
|
|
||||||
line: 2,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn main() {}
|
|
16
tests/ui/self/dispatch-from-dyn-layout-2.rs
Normal file
16
tests/ui/self/dispatch-from-dyn-layout-2.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
//@ check-pass
|
||||||
|
// Regression test for #90110.
|
||||||
|
|
||||||
|
// Make sure that object safety checking doesn't freak out when
|
||||||
|
// we have impossible-to-satisfy `Sized` predicates.
|
||||||
|
|
||||||
|
trait Parser
|
||||||
|
where
|
||||||
|
for<'a> (dyn Parser + 'a): Sized,
|
||||||
|
{
|
||||||
|
fn parse_line(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(_: &dyn Parser) {}
|
||||||
|
|
||||||
|
fn main() {}
|
19
tests/ui/self/dispatch-from-dyn-layout-3.rs
Normal file
19
tests/ui/self/dispatch-from-dyn-layout-3.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// Make sure that object safety checking doesn't freak out when
|
||||||
|
// we have impossible-to-satisfy `DispatchFromDyn` predicates.
|
||||||
|
|
||||||
|
#![feature(dispatch_from_dyn)]
|
||||||
|
#![feature(arbitrary_self_types)]
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ops::DispatchFromDyn;
|
||||||
|
|
||||||
|
trait Trait<T: Deref<Target = Self>>
|
||||||
|
where
|
||||||
|
for<'a> &'a T: DispatchFromDyn<&'a T>,
|
||||||
|
{
|
||||||
|
fn foo(self: &T) -> Box<dyn Trait<T>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,4 +1,8 @@
|
||||||
//@ known-bug: #57276
|
//@ check-pass
|
||||||
|
// Regression test for #57276.
|
||||||
|
|
||||||
|
// Make sure that object safety checking doesn't freak out when
|
||||||
|
// we have impossible-to-satisfy `DispatchFromDyn` predicates.
|
||||||
|
|
||||||
#![feature(arbitrary_self_types, dispatch_from_dyn)]
|
#![feature(arbitrary_self_types, dispatch_from_dyn)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue