Skip to content

Commit 1eb1a24

Browse files
Auto merge of #142941 - compiler-errors:shallow-bail, r=<try>
[perf] Shallowly bail from `coerce_unsized` more
2 parents 36b2163 + 3d115ac commit 1eb1a24

File tree

1 file changed

+41
-5
lines changed

1 file changed

+41
-5
lines changed

compiler/rustc_hir_typeck/src/coercion.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
515515
///
516516
/// [unsized coercion](https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions)
517517
#[instrument(skip(self), level = "debug")]
518-
fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceResult<'tcx> {
519-
source = self.shallow_resolve(source);
520-
target = self.shallow_resolve(target);
521-
debug!(?source, ?target);
522-
518+
fn coerce_unsized(&self, source: Ty<'tcx>, target: Ty<'tcx>) -> CoerceResult<'tcx> {
523519
// We don't apply any coercions incase either the source or target
524520
// aren't sufficiently well known but tend to instead just equate
525521
// them both.
@@ -532,6 +528,46 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
532528
return Err(TypeError::Mismatch);
533529
}
534530

531+
// These targets are known to never be RHS in `LHS: CoerceUnsized<RHS>`.
532+
// That's because these are built-in types for which a core-provided impl
533+
// doesn't exist, and for which a user-written impl is invalid.
534+
//
535+
// This is technically incomplete when users write impossible bounds like
536+
// `where T: CoerceUnsized<usize>`, for example, but that trait is unstable
537+
// and coercion is allowed to be incomplete. The only case where this matters
538+
// is impossible bounds.
539+
match target.kind() {
540+
ty::Bool
541+
| ty::Char
542+
| ty::Int(_)
543+
| ty::Uint(_)
544+
| ty::Float(_)
545+
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
546+
| ty::Str
547+
| ty::Array(_, _)
548+
| ty::Slice(_)
549+
| ty::FnDef(_, _)
550+
| ty::FnPtr(_, _)
551+
| ty::Dynamic(_, _, _)
552+
| ty::Closure(_, _)
553+
| ty::CoroutineClosure(_, _)
554+
| ty::Coroutine(_, _)
555+
| ty::CoroutineWitness(_, _)
556+
| ty::Never
557+
| ty::Tuple(_) => return Err(TypeError::Mismatch),
558+
_ => {}
559+
}
560+
// Additionally, we ignore `&str -> &str` coercions, which happen very
561+
// commonly since strings are one of the most used argument types in Rust,
562+
// we do coercions when type checking call expressions.
563+
if let ty::Ref(_, source_pointee, ty::Mutability::Not) = *source.kind()
564+
&& source_pointee.is_str()
565+
&& let ty::Ref(_, target_pointee, ty::Mutability::Not) = *target.kind()
566+
&& target_pointee.is_str()
567+
{
568+
return Err(TypeError::Mismatch);
569+
}
570+
535571
let traits =
536572
(self.tcx.lang_items().unsize_trait(), self.tcx.lang_items().coerce_unsized_trait());
537573
let (Some(unsize_did), Some(coerce_unsized_did)) = traits else {

0 commit comments

Comments
 (0)