Skip to content

Commit 1bb0baa

Browse files
committed
Elaborate bounds before checking impl correctness
1 parent 32ee2ea commit 1bb0baa

4 files changed

Lines changed: 73 additions & 73 deletions

File tree

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1346,7 +1346,11 @@ pub fn suggest_impl_trait<'tcx>(
13461346

13471347
fn impl_is_fully_generic_for_reflection(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
13481348
tcx.impl_trait_header(def_id).is_fully_generic_for_reflection()
1349-
&& tcx.explicit_predicates_of(def_id).is_fully_generic_for_reflection()
1349+
&& rustc_trait_selection::traits::elaborate(
1350+
tcx,
1351+
tcx.predicates_of(def_id).instantiate_identity(tcx).into_iter(),
1352+
)
1353+
.all(|(clause, _)| clause.is_fully_generic_for_reflection())
13501354
}
13511355

13521356
fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader<'_> {

compiler/rustc_middle/src/ty/generics.rs

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1-
use std::ops::ControlFlow;
2-
31
use rustc_ast as ast;
42
use rustc_data_structures::fx::FxHashMap;
53
use rustc_hir::def_id::DefId;
64
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
75
use rustc_span::{Span, Symbol, kw};
8-
use rustc_type_ir::{TypeSuperVisitable as _, TypeVisitable, TypeVisitor};
96
use tracing::instrument;
107

118
use super::{Clause, InstantiatedPredicates, ParamConst, ParamTy, Ty, TyCtxt};
12-
use crate::ty::{self, ClauseKind, EarlyBinder, GenericArgsRef, Region, RegionKind, TyKind};
9+
use crate::ty::{self, EarlyBinder, GenericArgsRef};
1310

1411
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
1512
pub enum GenericParamDefKind {
@@ -423,70 +420,6 @@ impl<'tcx> GenericPredicates<'tcx> {
423420
instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p));
424421
instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s));
425422
}
426-
427-
/// Allow simple where bounds like `T: Debug`, but prevent any kind of
428-
/// outlives bounds or uses of generic parameters on the right hand side.
429-
pub fn is_fully_generic_for_reflection(self) -> bool {
430-
struct ParamChecker;
431-
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamChecker {
432-
type Result = ControlFlow<()>;
433-
fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result {
434-
match r.kind() {
435-
RegionKind::ReEarlyParam(_) | RegionKind::ReStatic | RegionKind::ReError(_) => {
436-
ControlFlow::Break(())
437-
}
438-
RegionKind::ReVar(_)
439-
| RegionKind::RePlaceholder(_)
440-
| RegionKind::ReErased
441-
| RegionKind::ReLateParam(_) => {
442-
bug!("unexpected lifetime in impl: {r:?}")
443-
}
444-
RegionKind::ReBound(..) => ControlFlow::Continue(()),
445-
}
446-
}
447-
448-
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
449-
match t.kind() {
450-
TyKind::Param(_p) => {
451-
// Reject using parameters used in the type in where bounds
452-
return ControlFlow::Break(());
453-
}
454-
TyKind::Alias(..) => return ControlFlow::Break(()),
455-
_ => (),
456-
}
457-
t.super_visit_with(self)
458-
}
459-
}
460-
461-
// Pessimistic: if any of the parameters have where bounds
462-
// don't allow this impl to be used.
463-
self.predicates.iter().all(|(clause, _)| {
464-
match clause.kind().skip_binder() {
465-
ClauseKind::Trait(trait_predicate) => {
466-
// In a `T: Trait`, if the rhs bound does not contain any generic params
467-
// or 'static lifetimes, then it cannot transitively cause such requirements,
468-
// considering we apply the fully-generic-for-reflection rules to any impls for
469-
// that trait, too.
470-
if matches!(trait_predicate.self_ty().kind(), ty::Param(_))
471-
&& trait_predicate.trait_ref.args[1..]
472-
.iter()
473-
.all(|arg| arg.visit_with(&mut ParamChecker).is_continue())
474-
{
475-
return true;
476-
}
477-
}
478-
ClauseKind::RegionOutlives(_)
479-
| ClauseKind::TypeOutlives(_)
480-
| ClauseKind::Projection(_)
481-
| ClauseKind::ConstArgHasType(_, _)
482-
| ClauseKind::WellFormed(_)
483-
| ClauseKind::ConstEvaluatable(_)
484-
| ClauseKind::HostEffect(_)
485-
| ClauseKind::UnstableFeature(_) => {}
486-
}
487-
clause.visit_with(&mut ParamChecker).is_continue()
488-
})
489-
}
490423
}
491424

492425
/// `[const]` bounds for a given item. This is represented using a struct much like

compiler/rustc_middle/src/ty/predicate.rs

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use std::cmp::Ordering;
2+
use std::ops::ControlFlow;
23

34
use rustc_data_structures::intern::Interned;
45
use rustc_hir::def_id::DefId;
56
use rustc_macros::{HashStable, extension};
6-
use rustc_type_ir as ir;
7+
use rustc_type_ir::{self as ir, TypeSuperVisitable as _, TypeVisitable as _, TypeVisitor};
78

89
use crate::ty::{
9-
self, DebruijnIndex, EarlyBinder, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom, WithCachedTypeInfo,
10+
self, DebruijnIndex, EarlyBinder, Region, RegionKind, Ty, TyCtxt, TypeFlags, Upcast,
11+
UpcastFrom, WithCachedTypeInfo,
1012
};
1113

1214
pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
@@ -215,6 +217,68 @@ impl<'tcx> Clause<'tcx> {
215217
None
216218
}
217219
}
220+
221+
/// Allow simple where bounds like `T: Debug`, but prevent any kind of
222+
/// outlives bounds or uses of generic parameters on the right hand side.
223+
pub fn is_fully_generic_for_reflection(self) -> bool {
224+
struct ParamChecker;
225+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParamChecker {
226+
type Result = ControlFlow<()>;
227+
fn visit_region(&mut self, r: Region<'tcx>) -> Self::Result {
228+
match r.kind() {
229+
RegionKind::ReEarlyParam(_) | RegionKind::ReStatic | RegionKind::ReError(_) => {
230+
ControlFlow::Break(())
231+
}
232+
RegionKind::ReVar(_)
233+
| RegionKind::RePlaceholder(_)
234+
| RegionKind::ReErased
235+
| RegionKind::ReLateParam(_) => {
236+
bug!("unexpected lifetime in impl: {r:?}")
237+
}
238+
RegionKind::ReBound(..) => ControlFlow::Continue(()),
239+
}
240+
}
241+
242+
fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
243+
match t.kind() {
244+
ty::Param(_p) => {
245+
// Reject using parameters used in the type in where bounds
246+
return ControlFlow::Break(());
247+
}
248+
ty::Alias(..) => return ControlFlow::Break(()),
249+
_ => (),
250+
}
251+
t.super_visit_with(self)
252+
}
253+
}
254+
255+
// Pessimistic: if any of the parameters have where bounds
256+
// don't allow this impl to be used.
257+
match self.kind().skip_binder() {
258+
ClauseKind::Trait(trait_predicate) => {
259+
// In a `T: Trait`, if the rhs bound does not contain any generic params
260+
// or 'static lifetimes, then it cannot transitively cause such requirements,
261+
// considering we apply the fully-generic-for-reflection rules to any impls for
262+
// that trait, too.
263+
if matches!(trait_predicate.self_ty().kind(), ty::Param(_))
264+
&& trait_predicate.trait_ref.args[1..]
265+
.iter()
266+
.all(|arg| arg.visit_with(&mut ParamChecker).is_continue())
267+
{
268+
return true;
269+
}
270+
}
271+
ClauseKind::RegionOutlives(_)
272+
| ClauseKind::TypeOutlives(_)
273+
| ClauseKind::Projection(_)
274+
| ClauseKind::ConstArgHasType(_, _)
275+
| ClauseKind::WellFormed(_)
276+
| ClauseKind::ConstEvaluatable(_)
277+
| ClauseKind::HostEffect(_)
278+
| ClauseKind::UnstableFeature(_) => {}
279+
}
280+
self.visit_with(&mut ParamChecker).is_continue()
281+
}
218282
}
219283

220284
impl<'tcx> rustc_type_ir::inherent::Clauses<TyCtxt<'tcx>> for ty::Clauses<'tcx> {}

tests/ui/any/try_as_dyn_elaborated_bounds.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ impl<T: Trait> Other for Foo<T> {}
1717

1818
const _: () = {
1919
let foo = Foo(());
20-
// TODO
21-
assert!(try_as_dyn::<Foo<()>, dyn Other>(&foo).is_some());
20+
assert!(try_as_dyn::<Foo<()>, dyn Other>(&foo).is_none());
2221
};
2322

2423
fn main() {}

0 commit comments

Comments
 (0)