From e57808d34f78d1c46176e3ef2681c8753a127542 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 31 Mar 2025 15:13:12 +0200 Subject: [PATCH 1/2] rarw --- compiler/rustc_hir_typeck/src/coercion.rs | 84 ++++++++++++----------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4cbc42b99ea35..4d44a7420940f 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -605,48 +605,52 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // However, we don't want to bail early all the time, since the unholdable obligations // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id`), // so we only bail if there (likely) is another way to convert the types. - if !self.infcx.predicate_may_hold(&root_obligation) { - if let Some(dyn_metadata_adt_def_id) = self.tcx.lang_items().get(LangItem::DynMetadata) - && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata) - { - self.probe(|_| { - let ocx = ObligationCtxt::new(&self.infcx); - - // returns `true` if `::Metadata` is `DynMetadata<_>` - let has_dyn_trait_metadata = |ty| { - let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty( - &ObligationCause::dummy(), - self.fcx.param_env, - Ty::new_alias( - self.tcx, - ty::AliasTyKind::Projection, - AliasTy::new(self.tcx, metadata_type_def_id, [ty]), - ), - ); + if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() + && let &ty::RawPtr(target_pointee, _) = target.kind() + { + if !self.infcx.predicate_may_hold(&root_obligation) { + if let Some(dyn_metadata_adt_def_id) = + self.tcx.lang_items().get(LangItem::DynMetadata) + && let Some(metadata_type_def_id) = + self.tcx.lang_items().get(LangItem::Metadata) + { + self.probe(|_| { + let ocx = ObligationCtxt::new(&self.infcx); + + // returns `true` if `::Metadata` is `DynMetadata<_>` + let has_dyn_trait_metadata = |ty| { + let metadata_ty: Result<_, _> = ocx.structurally_normalize_ty( + &ObligationCause::dummy(), + self.fcx.param_env, + Ty::new_alias( + self.tcx, + ty::AliasTyKind::Projection, + AliasTy::new(self.tcx, metadata_type_def_id, [ty]), + ), + ); - metadata_ty.is_ok_and(|metadata_ty| { - metadata_ty - .ty_adt_def() - .is_some_and(|d| d.did() == dyn_metadata_adt_def_id) - }) - }; - - // If both types are raw pointers to a (wrapper over a) trait object, - // this might be a cast like `*const W -> *const dyn Trait`. - // So it's better to bail and try that. (even if the cast is not possible, for - // example due to vtables not matching, cast diagnostic will likely still be better) - // - // N.B. use `target`, not `coerce_target` (the latter is a var) - if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() - && let &ty::RawPtr(target_pointee, _) = target.kind() - && has_dyn_trait_metadata(source_pointee) - && has_dyn_trait_metadata(target_pointee) - { - return Err(TypeError::Mismatch); - } + metadata_ty.is_ok_and(|metadata_ty| { + metadata_ty + .ty_adt_def() + .is_some_and(|d| d.did() == dyn_metadata_adt_def_id) + }) + }; - Ok(()) - })?; + // If both types are raw pointers to a (wrapper over a) trait object, + // this might be a cast like `*const W -> *const dyn Trait`. + // So it's better to bail and try that. (even if the cast is not possible, for + // example due to vtables not matching, cast diagnostic will likely still be better) + // + // N.B. use `target`, not `coerce_target` (the latter is a var) + if has_dyn_trait_metadata(source_pointee) + && has_dyn_trait_metadata(target_pointee) + { + return Err(TypeError::Mismatch); + } + + Ok(()) + })?; + } } } From 363d33937cd713dcaf63a41c77a98f113c2e33d5 Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 31 Mar 2025 15:22:06 +0200 Subject: [PATCH 2/2] alternative 2 --- compiler/rustc_hir_typeck/src/coercion.rs | 32 ++++++++++++++--------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 4d44a7420940f..bfdc4a19534ff 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -58,6 +58,7 @@ use rustc_middle::ty::error::TypeError; use rustc_middle::ty::{self, AliasTy, GenericArgsRef, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Span}; use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::traits::EvaluationResult::*; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCause, ObligationCauseCode, ObligationCtxt, @@ -599,18 +600,25 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target]), ); - // If the root `Source: CoerceUnsized` obligation can't possibly hold, - // we don't have to assume that this is unsizing coercion (it will always lead to an error) - // - // However, we don't want to bail early all the time, since the unholdable obligations - // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id`), - // so we only bail if there (likely) is another way to convert the types. - if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() - && let &ty::RawPtr(target_pointee, _) = target.kind() - { - if !self.infcx.predicate_may_hold(&root_obligation) { - if let Some(dyn_metadata_adt_def_id) = - self.tcx.lang_items().get(LangItem::DynMetadata) + match self.infcx.evaluate_obligation_no_overflow(&root_obligation) { + // Fast path if we're definitely able to coerce. This allows us to use the + // cache of the `FulfillmentContext` and avoids manual calls to select. + EvaluatedToOk | EvaluatedToOkModuloRegions | EvaluatedToOkModuloOpaqueTypes => { + coercion.obligations.push(root_obligation); + return Ok(coercion); + } + EvaluatedToAmbig | EvaluatedToAmbigStackDependent => {} + EvaluatedToErr => { + // If the root `Source: CoerceUnsized` obligation can't possibly hold, + // we don't have to assume that this is unsizing coercion (it will always lead to an error) + // + // However, we don't want to bail early all the time, since the unholdable obligations + // may be interesting for diagnostics (such as trying to coerce `&T` to `&dyn Id`), + // so we only bail if there (likely) is another way to convert the types. + if let &ty::RawPtr(source_pointee, _) = coerce_source.kind() + && let &ty::RawPtr(target_pointee, _) = target.kind() + && let Some(dyn_metadata_adt_def_id) = + self.tcx.lang_items().get(LangItem::DynMetadata) && let Some(metadata_type_def_id) = self.tcx.lang_items().get(LangItem::Metadata) {