Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 7fccac3

Browse files
committed
Typecheck dyn* coercions
Also changes things to treat dyn* as a sized type, unlike dyn Trait.
1 parent 6c01273 commit 7fccac3

File tree

11 files changed

+148
-29
lines changed

11 files changed

+148
-29
lines changed

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use ty::util::IntTypeExt;
3131

3232
use rustc_type_ir::sty::TyKind::*;
3333
use rustc_type_ir::RegionKind as IrRegionKind;
34-
use rustc_type_ir::TyKind as IrTyKind;
34+
use rustc_type_ir::{TraitObjectRepresentation, TyKind as IrTyKind};
3535

3636
// Re-export the `TyKind` from `rustc_type_ir` here for convenience
3737
#[rustc_diagnostic_item = "TyKind"]
@@ -692,6 +692,9 @@ impl<'tcx> ExistentialPredicate<'tcx> {
692692
}
693693

694694
impl<'tcx> Binder<'tcx, ExistentialPredicate<'tcx>> {
695+
/// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
696+
/// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
697+
/// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
695698
pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Predicate<'tcx> {
696699
use crate::ty::ToPredicate;
697700
match self.skip_binder() {
@@ -1849,7 +1852,12 @@ impl<'tcx> Ty<'tcx> {
18491852

18501853
#[inline]
18511854
pub fn is_trait(self) -> bool {
1852-
matches!(self.kind(), Dynamic(..))
1855+
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Unsized))
1856+
}
1857+
1858+
#[inline]
1859+
pub fn is_dyn_star(self) -> bool {
1860+
matches!(self.kind(), Dynamic(_, _, TraitObjectRepresentation::Sized))
18531861
}
18541862

18551863
#[inline]

compiler/rustc_trait_selection/src/traits/object_safety.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId;
2020
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
2121
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
2222
use rustc_middle::ty::{
23-
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
24-
TraitObjectRepresentation,
23+
self, EarlyBinder, TraitObjectRepresentation, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
24+
TypeVisitor,
2525
};
2626
use rustc_middle::ty::{Predicate, ToPredicate};
2727
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;

compiler/rustc_trait_selection/src/traits/select/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ use rustc_middle::ty::fold::BottomUpFolder;
3838
use rustc_middle::ty::print::with_no_trimmed_paths;
3939
use rustc_middle::ty::relate::TypeRelation;
4040
use rustc_middle::ty::subst::{Subst, SubstsRef};
41+
use rustc_middle::ty::TraitObjectRepresentation;
4142
use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate};
4243
use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitable};
4344
use rustc_span::symbol::sym;
@@ -1865,6 +1866,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
18651866
| ty::Array(..)
18661867
| ty::Closure(..)
18671868
| ty::Never
1869+
| ty::Dynamic(_, _, TraitObjectRepresentation::Sized)
18681870
| ty::Error(_) => {
18691871
// safe for everything
18701872
Where(ty::Binder::dummy(Vec::new()))

compiler/rustc_typeck/src/astconv/mod.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
2828
use rustc_middle::middle::stability::AllowUnstable;
2929
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, Subst, SubstsRef};
3030
use rustc_middle::ty::GenericParamDefKind;
31+
use rustc_middle::ty::TraitObjectRepresentation;
3132
use rustc_middle::ty::{
3233
self, Const, DefIdTree, EarlyBinder, IsSuggestable, Ty, TyCtxt, TypeVisitable,
3334
};
34-
use rustc_middle::ty::{TraitObjectRepresentation};
3535
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
3636
use rustc_span::edition::Edition;
3737
use rustc_span::lev_distance::find_best_match_for_name;
@@ -1253,6 +1253,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
12531253
trait_bounds: &[hir::PolyTraitRef<'_>],
12541254
lifetime: &hir::Lifetime,
12551255
borrowed: bool,
1256+
representation: TraitObjectRepresentation,
12561257
) -> Ty<'tcx> {
12571258
let tcx = self.tcx();
12581259

@@ -1573,11 +1574,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
15731574
};
15741575
debug!("region_bound: {:?}", region_bound);
15751576

1576-
let ty = tcx.mk_dynamic(
1577-
existential_predicates,
1578-
region_bound,
1579-
TraitObjectRepresentation::Unsized, // FIXME: check whether the source syntax was dyn or dyn*
1580-
);
1577+
let ty = tcx.mk_dynamic(existential_predicates, region_bound, representation);
15811578
debug!("trait_object_type: {:?}", ty);
15821579
ty
15831580
}
@@ -2623,9 +2620,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
26232620
Some(ast_ty),
26242621
))
26252622
}
2626-
hir::TyKind::TraitObject(bounds, ref lifetime, _) => {
2623+
hir::TyKind::TraitObject(bounds, ref lifetime, repr) => {
26272624
self.maybe_lint_bare_trait(ast_ty, in_path);
2628-
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed)
2625+
let repr = match repr {
2626+
TraitObjectSyntax::Dyn | TraitObjectSyntax::None => {
2627+
TraitObjectRepresentation::Unsized
2628+
}
2629+
TraitObjectSyntax::DynStar => TraitObjectRepresentation::Sized,
2630+
};
2631+
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime, borrowed, repr)
26292632
}
26302633
hir::TyKind::Path(hir::QPath::Resolved(ref maybe_qself, ref path)) => {
26312634
debug!(?maybe_qself, ?path);

compiler/rustc_typeck/src/check/cast.rs

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ use crate::type_error_struct;
3535
use hir::def_id::LOCAL_CRATE;
3636
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
3737
use rustc_hir as hir;
38+
use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
3839
use rustc_middle::mir::Mutability;
3940
use rustc_middle::ty::adjustment::AllowTwoPhase;
4041
use rustc_middle::ty::cast::{CastKind, CastTy};
4142
use rustc_middle::ty::error::TypeError;
4243
use rustc_middle::ty::subst::SubstsRef;
43-
use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
44+
use rustc_middle::ty::{
45+
self, Binder, TraitObjectRepresentation, Ty, TypeAndMut, TypeVisitable, VariantDef,
46+
};
4447
use rustc_session::lint;
4548
use rustc_session::Session;
4649
use rustc_span::symbol::sym;
@@ -52,9 +55,12 @@ use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
5255
/// a function context.
5356
#[derive(Debug)]
5457
pub struct CastCheck<'tcx> {
58+
/// The expression whose value is being casted
5559
expr: &'tcx hir::Expr<'tcx>,
60+
/// The source type for the cast expression
5661
expr_ty: Ty<'tcx>,
5762
expr_span: Span,
63+
/// The target type. That is, the type we are casting to.
5864
cast_ty: Ty<'tcx>,
5965
cast_span: Span,
6066
span: Span,
@@ -199,8 +205,76 @@ fn make_invalid_casting_error<'a, 'tcx>(
199205
)
200206
}
201207

208+
pub enum CastCheckResult<'tcx> {
209+
Ok,
210+
Deferred(CastCheck<'tcx>),
211+
Err(ErrorGuaranteed),
212+
}
213+
214+
pub fn check_cast<'tcx>(
215+
fcx: &FnCtxt<'_, 'tcx>,
216+
expr: &'tcx hir::Expr<'tcx>,
217+
expr_ty: Ty<'tcx>,
218+
cast_ty: Ty<'tcx>,
219+
cast_span: Span,
220+
span: Span,
221+
) -> CastCheckResult<'tcx> {
222+
if cast_ty.is_dyn_star() {
223+
check_dyn_star_cast(fcx, expr, expr_ty, cast_ty)
224+
} else {
225+
match CastCheck::new(fcx, expr, expr_ty, cast_ty, cast_span, span) {
226+
Ok(check) => CastCheckResult::Deferred(check),
227+
Err(e) => CastCheckResult::Err(e),
228+
}
229+
}
230+
}
231+
232+
fn check_dyn_star_cast<'tcx>(
233+
fcx: &FnCtxt<'_, 'tcx>,
234+
expr: &'tcx hir::Expr<'tcx>,
235+
expr_ty: Ty<'tcx>,
236+
cast_ty: Ty<'tcx>,
237+
) -> CastCheckResult<'tcx> {
238+
// Find the bounds in the dyn*. For eaxmple, if we have
239+
//
240+
// let x = 22_usize as dyn* (Clone + Debug + 'static)
241+
//
242+
// this would return `existential_predicates = [?Self: Clone, ?Self: Debug]` and `region = 'static`.
243+
let (existential_predicates, region) = match cast_ty.kind() {
244+
ty::Dynamic(predicates, region, TraitObjectRepresentation::Sized) => (predicates, region),
245+
_ => panic!("Invalid dyn* cast_ty"),
246+
};
247+
248+
let cause = ObligationCause::new(
249+
expr.span,
250+
fcx.body_id,
251+
// FIXME: Use a better obligation cause code
252+
ObligationCauseCode::MiscObligation,
253+
);
254+
255+
// For each existential predicate (e.g., `?Self: Clone`) substitute
256+
// the type of the expression (e.g., `usize` in our example above)
257+
// and then require that the resulting predicate (e.g., `usize: Clone`)
258+
// holds (it does).
259+
for existential_predicate in existential_predicates.iter() {
260+
let predicate = existential_predicate.with_self_ty(fcx.tcx, expr_ty);
261+
fcx.register_predicate(Obligation::new(cause.clone(), fcx.param_env, predicate));
262+
}
263+
264+
// Enforce the region bound `'static` (e.g., `usize: 'static`, in our example).
265+
fcx.register_predicate(Obligation::new(
266+
cause,
267+
fcx.param_env,
268+
fcx.tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
269+
ty::OutlivesPredicate(expr_ty, *region),
270+
))),
271+
));
272+
273+
CastCheckResult::Ok
274+
}
275+
202276
impl<'a, 'tcx> CastCheck<'tcx> {
203-
pub fn new(
277+
fn new(
204278
fcx: &FnCtxt<'a, 'tcx>,
205279
expr: &'tcx hir::Expr<'tcx>,
206280
expr_ty: Ty<'tcx>,
@@ -215,7 +289,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
215289
// cases now. We do a more thorough check at the end, once
216290
// inference is more completely known.
217291
match cast_ty.kind() {
218-
ty::Dynamic(..) | ty::Slice(..) => {
292+
ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Slice(..) => {
219293
let reported = check.report_cast_to_unsized_type(fcx);
220294
Err(reported)
221295
}

compiler/rustc_typeck/src/check/expr.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,15 @@
33
//! See `mod.rs` for more context on type checking in general.
44
55
use crate::astconv::AstConv as _;
6-
use crate::check::cast;
6+
use crate::check::cast::{self, CastCheckResult};
77
use crate::check::coercion::CoerceMany;
88
use crate::check::fatally_break_rust;
99
use crate::check::method::SelfSource;
10-
use crate::check::report_unexpected_variant_res;
11-
use crate::check::BreakableCtxt;
12-
use crate::check::Diverges;
13-
use crate::check::DynamicCoerceMany;
1410
use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExpectation};
15-
use crate::check::FnCtxt;
16-
use crate::check::Needs;
17-
use crate::check::TupleArgumentsFlag::DontTupleArguments;
11+
use crate::check::{
12+
report_unexpected_variant_res, BreakableCtxt, Diverges, DynamicCoerceMany, FnCtxt, Needs,
13+
TupleArgumentsFlag::DontTupleArguments,
14+
};
1815
use crate::errors::{
1916
FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct,
2017
YieldExprOutsideOfGenerator,
@@ -1252,16 +1249,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
12521249
} else {
12531250
// Defer other checks until we're done type checking.
12541251
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
1255-
match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
1256-
Ok(cast_check) => {
1252+
match cast::check_cast(self, e, t_expr, t_cast, t.span, expr.span) {
1253+
CastCheckResult::Ok => t_cast,
1254+
CastCheckResult::Deferred(cast_check) => {
12571255
debug!(
12581256
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
12591257
t_cast, t_expr, cast_check,
12601258
);
12611259
deferred_cast_checks.push(cast_check);
12621260
t_cast
12631261
}
1264-
Err(_) => self.tcx.ty_error(),
1262+
CastCheckResult::Err(ErrorGuaranteed { .. }) => self.tcx.ty_error(),
12651263
}
12661264
}
12671265
}

compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182182
}
183183
})
184184
}
185-
ty::Dynamic(data, _) => {
185+
ty::Dynamic(data, _, ty::TraitObjectRepresentation::Unsized) => {
186186
data.iter().find_map(|pred| {
187187
if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
188188
&& Some(proj.item_def_id) == self.tcx.lang_items().fn_once_output()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![feature(async_fn_in_traits)]
2+
3+
use std::fmt::Debug;
4+
5+
trait Foo {}
6+
7+
fn make_dyn_star() {
8+
let i = 42;
9+
let dyn_i: dyn* Foo = i as dyn* Foo; //~ ERROR trait bound `{integer}: Foo` is not satisfied
10+
}
11+
12+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0277]: the trait bound `{integer}: Foo` is not satisfied
2+
--> $DIR/dyn-star-trait-error.rs:9:27
3+
|
4+
LL | let dyn_i: dyn* Foo = i as dyn* Foo;
5+
| ^ the trait `Foo` is not implemented for `{integer}`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0277`.

src/test/ui/dyn-star/make-dyn-star.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// check-pass
2+
#![feature(dyn_star)]
3+
4+
use std::fmt::Debug;
5+
6+
pub fn dyn_star_parameter(_: dyn* Send) {
7+
}
8+
9+
fn make_dyn_star() {
10+
let i = 42usize;
11+
let dyn_i: dyn* Debug = i as dyn* Debug;
12+
}
13+
14+
fn main() {}

src/test/ui/dyn-star/syntax.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
//
33
// check-pass
44

5-
65
#![feature(dyn_star)]
76

8-
pub fn dyn_star_parameter(_: &dyn* Send) {
7+
pub fn dyn_star_parameter(_: dyn* Send) {
98
}
109

1110
fn main() {}

0 commit comments

Comments
 (0)