1
Fork 0

Do not rely on type_var_origin in OrphanCheckErr::NonLocalInputType

This commit is contained in:
Michael Goulet 2025-03-20 01:59:38 +00:00
parent 2947be7af8
commit 220851cc75
6 changed files with 60 additions and 64 deletions

View file

@ -3,11 +3,10 @@
use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION; use rustc_lint_defs::builtin::UNCOVERED_PARAM_IN_PROJECTION;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode,
}; };
use rustc_middle::{bug, span_bug}; use rustc_middle::{bug, span_bug};
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::{DefId, LocalDefId};
@ -356,13 +355,20 @@ fn orphan_check<'tcx>(
}) })
} }
OrphanCheckErr::NonLocalInputType(tys) => { OrphanCheckErr::NonLocalInputType(tys) => {
let generics = tcx.generics_of(impl_def_id); let tys = infcx.probe(|_| {
let tys = tys // Map the unconstrained args back to their params,
.into_iter() // ignoring any type unification errors.
.map(|(ty, is_target_ty)| { for (arg, id_arg) in
(ty.fold_with(&mut TyVarReplacer { infcx: &infcx, generics }), is_target_ty) std::iter::zip(args, ty::GenericArgs::identity_for_item(tcx, impl_def_id))
}) {
.collect(); let _ = infcx.at(&cause, ty::ParamEnv::empty()).eq(
DefineOpaqueTypes::No,
arg,
id_arg,
);
}
infcx.resolve_vars_if_possible(tys)
});
OrphanCheckErr::NonLocalInputType(tys) OrphanCheckErr::NonLocalInputType(tys)
} }
}) })
@ -536,40 +542,3 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> {
} }
} }
} }
struct TyVarReplacer<'cx, 'tcx> {
infcx: &'cx InferCtxt<'tcx>,
generics: &'tcx ty::Generics,
}
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> {
fn cx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
return ty;
}
let ty::Infer(ty::TyVar(vid)) = *ty.kind() else {
return ty.super_fold_with(self);
};
let origin = self.infcx.type_var_origin(vid);
if let Some(def_id) = origin.param_def_id {
// The generics of an `impl` don't have a parent, we can index directly.
let index = self.generics.param_def_id_to_index[&def_id];
let name = self.generics.own_params[index as usize].name;
Ty::new_param(self.infcx.tcx, index, name)
} else {
ty
}
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
if !ct.has_type_flags(ty::TypeFlags::HAS_TY_INFER) {
return ct;
}
ct.super_fold_with(self)
}
}

View file

@ -4,7 +4,8 @@ use std::ops::ControlFlow;
use derive_where::derive_where; use derive_where::derive_where;
use rustc_type_ir::inherent::*; use rustc_type_ir::inherent::*;
use rustc_type_ir::{ use rustc_type_ir::{
self as ty, InferCtxtLike, Interner, TypeVisitable, TypeVisitableExt, TypeVisitor, self as ty, InferCtxtLike, Interner, TrivialTypeTraversalImpls, TypeVisitable,
TypeVisitableExt, TypeVisitor,
}; };
use tracing::instrument; use tracing::instrument;
@ -95,6 +96,8 @@ pub fn trait_ref_is_local_or_fundamental<I: Interner>(tcx: I, trait_ref: ty::Tra
trait_ref.def_id.is_local() || tcx.trait_is_fundamental(trait_ref.def_id) trait_ref.def_id.is_local() || tcx.trait_is_fundamental(trait_ref.def_id)
} }
TrivialTypeTraversalImpls! { IsFirstInputType, }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum IsFirstInputType { pub enum IsFirstInputType {
No, No,

View file

@ -1,10 +1,11 @@
/// Used for types that are `Copy` and which **do not care arena /// Used for types that are `Copy` and which **do not care arena
/// allocated data** (i.e., don't need to be folded). /// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! TrivialTypeTraversalImpls { macro_rules! TrivialTypeTraversalImpls {
($($ty:ty,)+) => { ($($ty:ty,)+) => {
$( $(
impl<I: $crate::Interner> $crate::fold::TypeFoldable<I> for $ty { impl<I: $crate::Interner> $crate::TypeFoldable<I> for $ty {
fn try_fold_with<F: $crate::fold::FallibleTypeFolder<I>>( fn try_fold_with<F: $crate::FallibleTypeFolder<I>>(
self, self,
_: &mut F, _: &mut F,
) -> ::std::result::Result<Self, F::Error> { ) -> ::std::result::Result<Self, F::Error> {
@ -12,7 +13,7 @@ macro_rules! TrivialTypeTraversalImpls {
} }
#[inline] #[inline]
fn fold_with<F: $crate::fold::TypeFolder<I>>( fn fold_with<F: $crate::TypeFolder<I>>(
self, self,
_: &mut F, _: &mut F,
) -> Self { ) -> Self {
@ -20,14 +21,14 @@ macro_rules! TrivialTypeTraversalImpls {
} }
} }
impl<I: $crate::Interner> $crate::visit::TypeVisitable<I> for $ty { impl<I: $crate::Interner> $crate::TypeVisitable<I> for $ty {
#[inline] #[inline]
fn visit_with<F: $crate::visit::TypeVisitor<I>>( fn visit_with<F: $crate::TypeVisitor<I>>(
&self, &self,
_: &mut F) _: &mut F)
-> F::Result -> F::Result
{ {
<F::Result as rustc_ast_ir::visit::VisitorResult>::output() <F::Result as $crate::VisitorResult>::output()
} }
} }
)+ )+

View file

@ -1,10 +0,0 @@
//@ known-bug: #132826
pub trait MyTrait {
type Item;
}
impl<K> MyTrait for Vec<K> {
type Item = Vec<K>;
}
impl<K> From<Vec<K>> for <Vec<K> as MyTrait>::Item {}

View file

@ -0,0 +1,17 @@
// Regression test for #132826.
// Make sure we don't try to resolve the variable `K1` in the generics of the impl
// (which only has `K2`).
pub trait MyTrait {
type Item;
}
impl<K1> MyTrait for Vec<K1> {
type Item = Vec<K1>;
}
impl<K2> From<Vec<K2>> for <Vec<K2> as MyTrait>::Item {}
//~^ ERROR only traits defined in the current crate can be implemented for arbitrary types
fn main() {}

View file

@ -0,0 +1,16 @@
error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
--> $DIR/orphan-check-error-reporting-ty-var.rs:14:1
|
LL | impl<K2> From<Vec<K2>> for <Vec<K2> as MyTrait>::Item {}
| ^^^^^^^^^-------------^^^^^--------------------------
| | |
| | `Vec` is not defined in the current crate
| `Vec` is not defined in the current crate
|
= note: impl doesn't have any local type before any uncovered type parameters
= note: for more information see https://doc.rust-lang.org/reference/items/implementations.html#orphan-rules
= note: define and implement a trait or new type instead
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0117`.