|
10 | 10 |
|
11 | 11 | use std::assert_matches::debug_assert_matches;
|
12 | 12 |
|
13 |
| -use min_specialization::check_min_specialization; |
| 13 | +use itertools::Itertools; |
14 | 14 | use rustc_data_structures::fx::FxHashSet;
|
15 | 15 | use rustc_errors::codes::*;
|
16 | 16 | use rustc_hir::def::DefKind;
|
17 |
| -use rustc_hir::def_id::LocalDefId; |
18 |
| -use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; |
19 |
| -use rustc_span::ErrorGuaranteed; |
| 17 | +use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; |
| 18 | +use rustc_infer::infer::TyCtxtInferExt; |
| 19 | +use rustc_lint_defs::builtin::DYN_OVERLAP; |
| 20 | +use rustc_middle::ty::{ |
| 21 | + self, ExistentialPredicateStableCmpExt, Ty, TyCtxt, TypeVisitableExt, TypingMode, Upcast, |
| 22 | + elaborate, |
| 23 | +}; |
| 24 | +use rustc_span::{DUMMY_SP, ErrorGuaranteed, sym}; |
| 25 | +use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; |
20 | 26 |
|
21 | 27 | use crate::constrained_generic_params as cgp;
|
22 | 28 | use crate::errors::UnconstrainedGenericParameter;
|
| 29 | +use crate::impl_wf_check::min_specialization::check_min_specialization; |
23 | 30 |
|
24 | 31 | mod min_specialization;
|
25 | 32 |
|
@@ -68,6 +75,22 @@ pub(crate) fn check_impl_wf(
|
68 | 75 | if tcx.features().min_specialization() {
|
69 | 76 | res = res.and(check_min_specialization(tcx, impl_def_id));
|
70 | 77 | }
|
| 78 | + |
| 79 | + if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id.to_def_id()) { |
| 80 | + for &subtrait_def_id in tcx |
| 81 | + .crates(()) |
| 82 | + .into_iter() |
| 83 | + .copied() |
| 84 | + .chain([LOCAL_CRATE]) |
| 85 | + .flat_map(|cnum| tcx.traits(cnum)) |
| 86 | + { |
| 87 | + if ty::elaborate::supertrait_def_ids(tcx, subtrait_def_id).contains(&trait_def_id) { |
| 88 | + tcx.ensure_ok() |
| 89 | + .lint_object_blanket_impl((impl_def_id.to_def_id(), subtrait_def_id)); |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + |
71 | 94 | res
|
72 | 95 | }
|
73 | 96 |
|
@@ -234,3 +257,120 @@ pub(crate) fn enforce_impl_non_lifetime_params_are_constrained(
|
234 | 257 | }
|
235 | 258 | res
|
236 | 259 | }
|
| 260 | + |
| 261 | +pub(crate) fn lint_object_blanket_impl<'tcx>( |
| 262 | + tcx: TyCtxt<'tcx>, |
| 263 | + (impl_def_id, trait_def_id): (DefId, DefId), |
| 264 | +) { |
| 265 | + if tcx.is_diagnostic_item(sym::Any, trait_def_id) { |
| 266 | + return; |
| 267 | + } |
| 268 | + |
| 269 | + if !tcx.is_dyn_compatible(trait_def_id) { |
| 270 | + return; |
| 271 | + } |
| 272 | + |
| 273 | + let infcx = tcx.infer_ctxt().with_next_trait_solver(true).build(TypingMode::CheckObjectOverlap); |
| 274 | + |
| 275 | + let principal_trait_args = infcx.fresh_args_for_item(DUMMY_SP, trait_def_id); |
| 276 | + let principal_trait = ty::TraitRef::new_from_args(tcx, trait_def_id, principal_trait_args); |
| 277 | + |
| 278 | + let mut needed_associated_types = vec![]; |
| 279 | + let clause: ty::Clause<'tcx> = ty::TraitRef::identity(tcx, trait_def_id).upcast(tcx); |
| 280 | + for clause in elaborate::elaborate(tcx, [clause]).filter_only_self() { |
| 281 | + let clause = clause.instantiate_supertrait(tcx, ty::Binder::dummy(principal_trait)); |
| 282 | + |
| 283 | + let bound_predicate = clause.kind(); |
| 284 | + match bound_predicate.skip_binder() { |
| 285 | + ty::ClauseKind::Trait(pred) => { |
| 286 | + // FIXME(negative_bounds): Handle this correctly... |
| 287 | + let trait_ref = tcx.anonymize_bound_vars(bound_predicate.rebind(pred.trait_ref)); |
| 288 | + needed_associated_types.extend( |
| 289 | + tcx.associated_items(pred.trait_ref.def_id) |
| 290 | + .in_definition_order() |
| 291 | + // We only care about associated types. |
| 292 | + .filter(|item| item.is_type()) |
| 293 | + // No RPITITs -- they're not dyn-compatible for now. |
| 294 | + .filter(|item| !item.is_impl_trait_in_trait()) |
| 295 | + // If the associated type has a `where Self: Sized` bound, |
| 296 | + // we do not need to constrain the associated type. |
| 297 | + .filter(|item| !tcx.generics_require_sized_self(item.def_id)) |
| 298 | + .map(|item| (item.def_id, trait_ref)), |
| 299 | + ); |
| 300 | + } |
| 301 | + _ => (), |
| 302 | + } |
| 303 | + } |
| 304 | + |
| 305 | + let mut data: Vec<_> = [ty::Binder::dummy(ty::ExistentialPredicate::Trait( |
| 306 | + ty::ExistentialTraitRef::erase_self_ty(tcx, principal_trait), |
| 307 | + ))] |
| 308 | + .into_iter() |
| 309 | + .chain(needed_associated_types.into_iter().map(|(def_id, trait_ref)| { |
| 310 | + trait_ref.map_bound(|trait_ref| { |
| 311 | + ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty( |
| 312 | + tcx, |
| 313 | + ty::ProjectionPredicate { |
| 314 | + projection_term: ty::AliasTerm::new_from_args(tcx, def_id, trait_ref.args), |
| 315 | + term: infcx.next_ty_var(DUMMY_SP).into(), |
| 316 | + }, |
| 317 | + )) |
| 318 | + }) |
| 319 | + })) |
| 320 | + .collect(); |
| 321 | + data.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); |
| 322 | + |
| 323 | + let self_ty = Ty::new_dynamic( |
| 324 | + tcx, |
| 325 | + tcx.mk_poly_existential_predicates(&data), |
| 326 | + tcx.lifetimes.re_erased, |
| 327 | + ty::Dyn, |
| 328 | + ); |
| 329 | + |
| 330 | + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); |
| 331 | + let impl_trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, impl_args); |
| 332 | + |
| 333 | + let ocx = ObligationCtxt::new(&infcx); |
| 334 | + let Ok(()) = |
| 335 | + ocx.eq(&ObligationCause::dummy(), ty::ParamEnv::empty(), principal_trait, impl_trait_ref) |
| 336 | + else { |
| 337 | + return; |
| 338 | + }; |
| 339 | + let Ok(()) = |
| 340 | + ocx.eq(&ObligationCause::dummy(), ty::ParamEnv::empty(), self_ty, impl_trait_ref.self_ty()) |
| 341 | + else { |
| 342 | + return; |
| 343 | + }; |
| 344 | + |
| 345 | + ocx.register_obligations( |
| 346 | + tcx.predicates_of(impl_def_id).instantiate(tcx, impl_args).into_iter().map( |
| 347 | + |(clause, _)| { |
| 348 | + Obligation::new(tcx, ObligationCause::dummy(), ty::ParamEnv::empty(), clause) |
| 349 | + }, |
| 350 | + ), |
| 351 | + ); |
| 352 | + |
| 353 | + if !ocx.select_where_possible().is_empty() { |
| 354 | + return; |
| 355 | + } |
| 356 | + |
| 357 | + let local_def_id = if let Some(impl_def_id) = impl_def_id.as_local() { |
| 358 | + impl_def_id |
| 359 | + } else if let Some(trait_def_id) = trait_def_id.as_local() { |
| 360 | + trait_def_id |
| 361 | + } else { |
| 362 | + panic!() |
| 363 | + }; |
| 364 | + let hir_id = tcx.local_def_id_to_hir_id(local_def_id); |
| 365 | + |
| 366 | + let self_ty = infcx.resolve_vars_if_possible(self_ty); |
| 367 | + |
| 368 | + tcx.node_span_lint(DYN_OVERLAP, hir_id, tcx.def_span(local_def_id), |diag| { |
| 369 | + diag.primary_message("hi"); |
| 370 | + diag.span_label( |
| 371 | + tcx.def_span(trait_def_id), |
| 372 | + format!("built-in `{self_ty}` implementation for this trait"), |
| 373 | + ); |
| 374 | + diag.span_label(tcx.def_span(impl_def_id), "overlaps with this blanket impl"); |
| 375 | + }); |
| 376 | +} |
0 commit comments