Typecheck dyn* coercions
Also changes things to treat dyn* as a sized type, unlike dyn Trait.
This commit is contained in:
parent
6c01273a15
commit
7fccac3ea0
@ -31,7 +31,7 @@
|
||||
|
||||
use rustc_type_ir::sty::TyKind::*;
|
||||
use rustc_type_ir::RegionKind as IrRegionKind;
|
||||
use rustc_type_ir::TyKind as IrTyKind;
|
||||
use rustc_type_ir::{TraitObjectRepresentation, TyKind as IrTyKind};
|
||||
|
||||
// Re-export the `TyKind` from `rustc_type_ir` here for convenience
|
||||
#[rustc_diagnostic_item = "TyKind"]
|
||||
@ -692,6 +692,9 @@ pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering {
|
||||
}
|
||||
|
||||
impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
|
||||
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
|
||||
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
|
||||
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
|
||||
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
|
||||
use crate::ty::ToPredicate;
|
||||
match self.skip_binder() {
|
||||
@ -1849,7 +1852,12 @@ pub fn is_floating_point(self) -> bool {
|
||||
|
||||
#[inline]
|
||||
pub fn is_trait(self) -> bool {
|
||||
matches!(self.kind(), Dynamic(..))
|
||||
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Unsized))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_dyn_star(self) -> bool {
|
||||
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Sized))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -20,8 +20,8 @@
|
||||
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
|
||||
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
|
||||
use rustc_middle::ty::{
|
||||
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
|
||||
TraitObjectRepresentation,
|
||||
self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
|
||||
TypeVisitor,
|
||||
};
|
||||
use rustc_middle::ty::{Predicate, ToPredicate};
|
||||
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
|
||||
|
@ -38,6 +38,7 @@
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::relate::TypeRelation;
|
||||
use rustc_middle::ty::subst::{Subst, SubstsRef};
|
||||
use rustc_middle::ty::TraitObjectRepresentation;
|
||||
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
|
||||
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
|
||||
use rustc_span::symbol::sym;
|
||||
@ -1865,6 +1866,7 @@ fn sized_conditions(
|
||||
| ty::Array(..)
|
||||
| ty::Closure(..)
|
||||
| ty::Never
|
||||
| ty::Dynamic(_, _, TraitObjectRepresentation::Sized)
|
||||
| ty::Error(_) => {
|
||||
// safe for everything
|
||||
Where(ty::Binder::dummy(Vec::new()))
|
||||
|
@ -28,10 +28,10 @@
|
||||
use rustc_middle::middle::stability::AllowUnstable;
|
||||
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
|
||||
use rustc_middle::ty::GenericParamDefKind;
|
||||
use rustc_middle::ty::TraitObjectRepresentation;
|
||||
use rustc_middle::ty::{
|
||||
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
|
||||
};
|
||||
use rustc_middle::ty::{TraitObjectRepresentation};
|
||||
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::lev_distance::find_best_match_for_name;
|
||||
@ -1253,6 +1253,7 @@ fn conv_object_ty_poly_trait_ref(
|
||||
trait_bounds: &[hir::PolyTraitRef<'_>],
|
||||
lifetime: &hir::Lifetime,
|
||||
borrowed: bool,
|
||||
representation: TraitObjectRepresentation,
|
||||
) -> Ty<'tcx> {
|
||||
let tcx = self.tcx();
|
||||
|
||||
@ -1573,11 +1574,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
|
||||
};
|
||||
debug!("region_bound: {:?}", region_bound);
|
||||
|
||||
let ty = tcx.mk_dynamic(
|
||||
existential_predicates,
|
||||
region_bound,
|
||||
TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn*
|
||||
);
|
||||
let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
|
||||
debug!("trait_object_type: {:?}", ty);
|
||||
ty
|
||||
}
|
||||
@ -2623,9 +2620,15 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
|
||||
Some(ast_ty),
|
||||
))
|
||||
}
|
||||
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
|
||||
hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
|
||||
self.maybe_lint_bare_trait(ast_ty, in_path);
|
||||
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
|
||||
let repr = match repr {
|
||||
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => {
|
||||
TraitObjectRepresentation::Unsized
|
||||
}
|
||||
TraitObjectSyntax::DynStar => TraitObjectRepresentation::Sized,
|
||||
};
|
||||
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
|
||||
}
|
||||
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
|
||||
debug!(?maybe_qself, ?path);
|
||||
|
@ -35,12 +35,15 @@
|
||||
use hir::def_id::LOCAL_CRATE;
|
||||
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
|
||||
use rustc_middle::mir::Mutability;
|
||||
use rustc_middle::ty::adjustment::AllowTwoPhase;
|
||||
use rustc_middle::ty::cast::{CastKind, CastTy};
|
||||
use rustc_middle::ty::error::TypeError;
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
|
||||
use rustc_middle::ty::{
|
||||
self, Binder, TraitObjectRepresentation, Ty, TypeAndMut, TypeVisitable, VariantDef,
|
||||
};
|
||||
use rustc_session::lint;
|
||||
use rustc_session::Session;
|
||||
use rustc_span::symbol::sym;
|
||||
@ -52,9 +55,12 @@
|
||||
/// a function context.
|
||||
#[derive(Debug)]
|
||||
pub struct CastCheck<'tcx> {
|
||||
/// The expression whose value is being casted
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
/// The source type for the cast expression
|
||||
expr_ty: Ty<'tcx>,
|
||||
expr_span: Span,
|
||||
/// The target type. That is, the type we are casting to.
|
||||
cast_ty: Ty<'tcx>,
|
||||
cast_span: Span,
|
||||
span: Span,
|
||||
@ -199,8 +205,76 @@ fn make_invalid_casting_error<'a, 'tcx>(
|
||||
)
|
||||
}
|
||||
|
||||
pub enum CastCheckResult<'tcx> {
|
||||
Ok,
|
||||
Deferred(CastCheck<'tcx>),
|
||||
Err(ErrorGuaranteed),
|
||||
}
|
||||
|
||||
pub fn check_cast<'tcx>(
|
||||
fcx: &FnCtxt<'_, 'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
cast_span: Span,
|
||||
span: Span,
|
||||
) -> CastCheckResult<'tcx> {
|
||||
if cast_ty.is_dyn_star() {
|
||||
check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
|
||||
} else {
|
||||
match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
|
||||
Ok(check) => CastCheckResult::Deferred(check),
|
||||
Err(e) => CastCheckResult::Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_dyn_star_cast<'tcx>(
|
||||
fcx: &FnCtxt<'_, 'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
) -> CastCheckResult<'tcx> {
|
||||
// Find the bounds in the dyn*. For eaxmple, if we have
|
||||
//
|
||||
// let x = 22_usize as dyn* (Clone + Debug + 'static)
|
||||
//
|
||||
// this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
|
||||
let (existential_predicates, region) = match cast_ty.kind() {
|
||||
ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region),
|
||||
_ => panic!("Invalid dyn* cast_ty"),
|
||||
};
|
||||
|
||||
let cause = ObligationCause::new(
|
||||
expr.span,
|
||||
fcx.body_id,
|
||||
// FIXME: Use a better obligation cause code
|
||||
ObligationCauseCode::MiscObligation,
|
||||
);
|
||||
|
||||
// For each existential predicate (e.g., `?Self: Clone`) substitute
|
||||
// the type of the expression (e.g., `usize` in our example above)
|
||||
// and then require that the resulting predicate (e.g., `usize: Clone`)
|
||||
// holds (it does).
|
||||
for existential_predicate in existential_predicates.iter() {
|
||||
let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
|
||||
fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
|
||||
}
|
||||
|
||||
// Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
|
||||
fcx.register_predicate(Obligation::new(
|
||||
cause,
|
||||
fcx.param_env,
|
||||
fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
|
||||
ty::OutlivesPredicate(expr_ty, *region),
|
||||
))),
|
||||
));
|
||||
|
||||
CastCheckResult::Ok
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> CastCheck<'tcx> {
|
||||
pub fn new(
|
||||
fn new(
|
||||
fcx: &FnCtxt<'a, 'tcx>,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
expr_ty: Ty<'tcx>,
|
||||
@ -215,7 +289,7 @@ pub fn new(
|
||||
// cases now. We do a more thorough check at the end, once
|
||||
// inference is more completely known.
|
||||
match cast_ty.kind() {
|
||||
ty::Dynamic(..) | ty::Slice(..) => {
|
||||
ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => {
|
||||
let reported = check.report_cast_to_unsized_type(fcx);
|
||||
Err(reported)
|
||||
}
|
||||
|
@ -3,18 +3,15 @@
|
||||
//! See `mod.rs` for more context on type checking in general.
|
||||
|
||||
use crate::astconv::AstConv as _;
|
||||
use crate::check::cast;
|
||||
use crate::check::cast::{self, CastCheckResult};
|
||||
use crate::check::coercion::CoerceMany;
|
||||
use crate::check::fatally_break_rust;
|
||||
use crate::check::method::SelfSource;
|
||||
use crate::check::report_unexpected_variant_res;
|
||||
use crate::check::BreakableCtxt;
|
||||
use crate::check::Diverges;
|
||||
use crate::check::DynamicCoerceMany;
|
||||
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
|
||||
use crate::check::FnCtxt;
|
||||
use crate::check::Needs;
|
||||
use crate::check::TupleArgumentsFlag::DontTupleArguments;
|
||||
use crate::check::{
|
||||
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
|
||||
TupleArgumentsFlag::DontTupleArguments,
|
||||
};
|
||||
use crate::errors::{
|
||||
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
|
||||
YieldExprOutsideOfGenerator,
|
||||
@ -1252,8 +1249,9 @@ fn check_expr_cast(
|
||||
} else {
|
||||
// Defer other checks until we're done type checking.
|
||||
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
|
||||
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||
Ok(cast_check) => {
|
||||
match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
|
||||
CastCheckResult::Ok => t_cast,
|
||||
CastCheckResult::Deferred(cast_check) => {
|
||||
debug!(
|
||||
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
|
||||
t_cast, t_expr, cast_check,
|
||||
@ -1261,7 +1259,7 @@ fn check_expr_cast(
|
||||
deferred_cast_checks.push(cast_check);
|
||||
t_cast
|
||||
}
|
||||
Err(_) => self.tcx.ty_error(),
|
||||
CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,7 @@ pub(in super::super) fn extract_callable_info(
|
||||
}
|
||||
})
|
||||
}
|
||||
ty::Dynamic(data, _) => {
|
||||
ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => {
|
||||
data.iter().find_map(|pred| {
|
||||
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
|
||||
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
|
||||
|
12
src/test/ui/async-await/dyn-star-trait-error.rs
Normal file
12
src/test/ui/async-await/dyn-star-trait-error.rs
Normal file
@ -0,0 +1,12 @@
|
||||
#![feature(async_fn_in_traits)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
trait Foo {}
|
||||
|
||||
fn make_dyn_star() {
|
||||
let i = 42;
|
||||
let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied
|
||||
}
|
||||
|
||||
fn main() {}
|
9
src/test/ui/async-await/dyn-star-trait-error.stderr
Normal file
9
src/test/ui/async-await/dyn-star-trait-error.stderr
Normal file
@ -0,0 +1,9 @@
|
||||
error[E0277]: the trait bound `{integer}: Foo` is not satisfied
|
||||
--> $DIR/dyn-star-trait-error.rs:9:27
|
||||
|
|
||||
LL | let dyn_i: dyn* Foo = i as dyn* Foo;
|
||||
| ^ the trait `Foo` is not implemented for `{integer}`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
14
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
14
src/test/ui/dyn-star/make-dyn-star.rs
Normal file
@ -0,0 +1,14 @@
|
||||
// check-pass
|
||||
#![feature(dyn_star)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub fn dyn_star_parameter(_: dyn* Send) {
|
||||
}
|
||||
|
||||
fn make_dyn_star() {
|
||||
let i = 42usize;
|
||||
let dyn_i: dyn* Debug = i as dyn* Debug;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -2,10 +2,9 @@
|
||||
//
|
||||
// check-pass
|
||||
|
||||
|
||||
#![feature(dyn_star)]
|
||||
|
||||
pub fn dyn_star_parameter(_: &dyn* Send) {
|
||||
pub fn dyn_star_parameter(_: dyn* Send) {
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
Loading…
Reference in New Issue
Block a user