Skip to content

Commit f87423c

Browse files
authored
Unrolled build for #154661
Rollup merge of #154661 - CoCo-Japan-pan:impl-restriction-check, r=jhpratt,Urgau Semantic checks of `impl` restrictions This PR implements semantic checks for `impl` restrictions proposed in the [Restrictions RFC](https://rust-lang.github.io/rfcs/3323-restrictions.html) (Tracking Issue #105077), and linked to a [GSOC idea/proposal](https://github.com/rust-lang/google-summer-of-code/tree/142433eb3b104b2f32bae0b9dfafb78a0a2ac579?tab=readme-ov-file#implementing-impl-and-mut-restrictions). It lowers the resolved paths of `impl` restrictions from the AST to HIR and into `TraitDef`, and integrates the checks into the coherence phase by extending `check_impl`. As parsing (#152943) and path resolution (#153556) have already been implemented, this PR provides a working implementation of `impl` restrictions. r? @Urgau cc @jhpratt
2 parents c7c14d4 + 46befd8 commit f87423c

30 files changed

Lines changed: 480 additions & 57 deletions

File tree

compiler/rustc_ast_lowering/src/item.rs

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ use tracing::instrument;
2424
use super::errors::{InvalidAbi, InvalidAbiSuggestion, TupleStructWithDefault, UnionWithDefault};
2525
use super::stability::{enabled_names, gate_unstable_abi};
2626
use super::{
27-
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
28-
RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
27+
AstOwner, FnDeclKind, GenericArgsMode, ImplTraitContext, ImplTraitPosition, LoweringContext,
28+
ParamMode, RelaxedBoundForbiddenReason, RelaxedBoundPolicy, ResolverAstLoweringExt,
2929
};
3030

3131
/// Wraps either IndexVec (during `hir_crate`), which acts like a primary
@@ -540,14 +540,14 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
540540
constness,
541541
is_auto,
542542
safety,
543-
// FIXME(impl_restrictions): lower to HIR
544-
impl_restriction: _,
543+
impl_restriction,
545544
ident,
546545
generics,
547546
bounds,
548547
items,
549548
}) => {
550549
let constness = self.lower_constness(*constness);
550+
let impl_restriction = self.lower_impl_restriction(impl_restriction);
551551
let ident = self.lower_ident(*ident);
552552
let (generics, (safety, items, bounds)) = self.lower_generics(
553553
generics,
@@ -566,7 +566,16 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
566566
(safety, items, bounds)
567567
},
568568
);
569-
hir::ItemKind::Trait(constness, *is_auto, safety, ident, generics, bounds, items)
569+
hir::ItemKind::Trait(
570+
constness,
571+
*is_auto,
572+
safety,
573+
impl_restriction,
574+
ident,
575+
generics,
576+
bounds,
577+
items,
578+
)
570579
}
571580
ItemKind::TraitAlias(box TraitAlias { constness, ident, generics, bounds }) => {
572581
let constness = self.lower_constness(*constness);
@@ -1831,6 +1840,38 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
18311840
}
18321841
}
18331842

1843+
pub(super) fn lower_impl_restriction(
1844+
&mut self,
1845+
r: &ImplRestriction,
1846+
) -> &'hir hir::ImplRestriction<'hir> {
1847+
let kind = match &r.kind {
1848+
RestrictionKind::Unrestricted => hir::RestrictionKind::Unrestricted,
1849+
RestrictionKind::Restricted { path, id, shorthand: _ } => {
1850+
let res = self.resolver.get_partial_res(*id);
1851+
if let Some(did) = res.and_then(|res| res.expect_full_res().opt_def_id()) {
1852+
hir::RestrictionKind::Restricted(self.arena.alloc(hir::Path {
1853+
res: did,
1854+
segments: self.arena.alloc_from_iter(path.segments.iter().map(|segment| {
1855+
self.lower_path_segment(
1856+
path.span,
1857+
segment,
1858+
ParamMode::Explicit,
1859+
GenericArgsMode::Err,
1860+
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
1861+
None,
1862+
)
1863+
})),
1864+
span: self.lower_span(path.span),
1865+
}))
1866+
} else {
1867+
self.dcx().span_delayed_bug(path.span, "should have errored in resolve");
1868+
hir::RestrictionKind::Unrestricted
1869+
}
1870+
}
1871+
};
1872+
self.arena.alloc(hir::ImplRestriction { kind, span: self.lower_span(r.span) })
1873+
}
1874+
18341875
/// Return the pair of the lowered `generics` as `hir::Generics` and the evaluation of `f` with
18351876
/// the carried impl trait definitions and bounds.
18361877
#[instrument(level = "debug", skip(self, f))]

compiler/rustc_hir/src/hir.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4341,13 +4341,14 @@ impl<'hir> Item<'hir> {
43414341
Constness,
43424342
IsAuto,
43434343
Safety,
4344+
&'hir ImplRestriction<'hir>,
43444345
Ident,
43454346
&'hir Generics<'hir>,
43464347
GenericBounds<'hir>,
43474348
&'hir [TraitItemId]
43484349
),
4349-
ItemKind::Trait(constness, is_auto, safety, ident, generics, bounds, items),
4350-
(*constness, *is_auto, *safety, *ident, generics, bounds, items);
4350+
ItemKind::Trait(constness, is_auto, safety, impl_restriction, ident, generics, bounds, items),
4351+
(*constness, *is_auto, *safety, impl_restriction, *ident, generics, bounds, items);
43514352

43524353
expect_trait_alias, (Constness, Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
43534354
ItemKind::TraitAlias(constness, ident, generics, bounds), (*constness, *ident, generics, bounds);
@@ -4416,6 +4417,20 @@ impl fmt::Display for Constness {
44164417
}
44174418
}
44184419

4420+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
4421+
pub struct ImplRestriction<'hir> {
4422+
pub kind: RestrictionKind<'hir>,
4423+
pub span: Span,
4424+
}
4425+
4426+
#[derive(Debug, Clone, Copy, HashStable_Generic)]
4427+
pub enum RestrictionKind<'hir> {
4428+
/// The restriction does not affect the item.
4429+
Unrestricted,
4430+
/// The restriction only applies outside of this path.
4431+
Restricted(&'hir Path<'hir, DefId>),
4432+
}
4433+
44194434
/// The actual safety specified in syntax. We may treat
44204435
/// its safety different within the type system to create a
44214436
/// "sound by default" system that needs checking this enum
@@ -4528,6 +4543,7 @@ pub enum ItemKind<'hir> {
45284543
Constness,
45294544
IsAuto,
45304545
Safety,
4546+
&'hir ImplRestriction<'hir>,
45314547
Ident,
45324548
&'hir Generics<'hir>,
45334549
GenericBounds<'hir>,
@@ -4578,7 +4594,7 @@ impl ItemKind<'_> {
45784594
| ItemKind::Enum(ident, ..)
45794595
| ItemKind::Struct(ident, ..)
45804596
| ItemKind::Union(ident, ..)
4581-
| ItemKind::Trait(_, _, _, ident, ..)
4597+
| ItemKind::Trait(_, _, _, _, ident, ..)
45824598
| ItemKind::TraitAlias(_, ident, ..) => Some(ident),
45834599

45844600
ItemKind::Use(_, UseKind::Glob | UseKind::ListStem)
@@ -4596,7 +4612,7 @@ impl ItemKind<'_> {
45964612
| ItemKind::Enum(_, generics, _)
45974613
| ItemKind::Struct(_, generics, _)
45984614
| ItemKind::Union(_, generics, _)
4599-
| ItemKind::Trait(_, _, _, _, generics, _, _)
4615+
| ItemKind::Trait(_, _, _, _, _, generics, _, _)
46004616
| ItemKind::TraitAlias(_, _, generics, _)
46014617
| ItemKind::Impl(Impl { generics, .. }) => generics,
46024618
_ => return None,

compiler/rustc_hir/src/intravisit.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,11 +632,15 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
632632
_constness,
633633
_is_auto,
634634
_safety,
635+
ref impl_restriction,
635636
ident,
636637
ref generics,
637638
bounds,
638639
trait_item_refs,
639640
) => {
641+
if let RestrictionKind::Restricted(path) = &impl_restriction.kind {
642+
walk_list!(visitor, visit_path_segment, path.segments);
643+
}
640644
try_visit!(visitor.visit_ident(ident));
641645
try_visit!(visitor.visit_generics(generics));
642646
walk_list!(visitor, visit_param_bound, bounds);

compiler/rustc_hir_analysis/src/coherence/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ fn enforce_trait_manually_implementable(
100100
return Err(tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span }));
101101
}
102102
}
103+
104+
if !trait_def.impl_restriction.is_allowed_in(impl_def_id.to_def_id(), tcx) {
105+
return Err(tcx.dcx().emit_err(errors::ImplOfRestrictedTrait {
106+
impl_span: impl_header_span,
107+
restriction_span: trait_def.impl_restriction.expect_span(),
108+
restriction_path: trait_def.impl_restriction.restriction_path(tcx),
109+
}));
110+
}
103111
Ok(())
104112
}
105113

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -893,11 +893,25 @@ fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> {
893893
fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
894894
let item = tcx.hir_expect_item(def_id);
895895

896-
let (constness, is_alias, is_auto, safety) = match item.kind {
897-
hir::ItemKind::Trait(constness, is_auto, safety, ..) => {
898-
(constness, false, is_auto == hir::IsAuto::Yes, safety)
899-
}
900-
hir::ItemKind::TraitAlias(constness, ..) => (constness, true, false, hir::Safety::Safe),
896+
let (constness, is_alias, is_auto, safety, impl_restriction) = match item.kind {
897+
hir::ItemKind::Trait(constness, is_auto, safety, impl_restriction, ..) => (
898+
constness,
899+
false,
900+
is_auto == hir::IsAuto::Yes,
901+
safety,
902+
if let hir::RestrictionKind::Restricted(path) = impl_restriction.kind {
903+
ty::trait_def::ImplRestrictionKind::Restricted(path.res, impl_restriction.span)
904+
} else {
905+
ty::trait_def::ImplRestrictionKind::Unrestricted
906+
},
907+
),
908+
hir::ItemKind::TraitAlias(constness, ..) => (
909+
constness,
910+
true,
911+
false,
912+
hir::Safety::Safe,
913+
ty::trait_def::ImplRestrictionKind::Unrestricted,
914+
),
901915
_ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
902916
};
903917

@@ -946,6 +960,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
946960
def_id: def_id.to_def_id(),
947961
safety,
948962
constness,
963+
impl_restriction,
949964
paren_sugar,
950965
has_auto_impl: is_auto,
951966
is_marker,

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
165165
Some(ty::Binder::dummy(tcx.impl_trait_ref(def_id).instantiate_identity()));
166166
}
167167
}
168-
ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
168+
ItemKind::Trait(_, _, _, _, _, _, self_bounds, ..)
169169
| ItemKind::TraitAlias(_, _, _, self_bounds) => {
170170
is_trait = Some((self_bounds, item.span));
171171
}
@@ -1038,7 +1038,7 @@ pub(super) fn const_conditions<'tcx>(
10381038
Node::Item(item) => match item.kind {
10391039
hir::ItemKind::Impl(impl_) => (impl_.generics, None, false),
10401040
hir::ItemKind::Fn { generics, .. } => (generics, None, false),
1041-
hir::ItemKind::Trait(_, _, _, _, generics, supertraits, _) => {
1041+
hir::ItemKind::Trait(_, _, _, _, _, generics, supertraits, _) => {
10421042
(generics, Some((Some(item.owner_id.def_id), supertraits)), false)
10431043
}
10441044
hir::ItemKind::TraitAlias(_, _, generics, supertraits) => {

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
645645
| hir::ItemKind::Enum(_, generics, _)
646646
| hir::ItemKind::Struct(_, generics, _)
647647
| hir::ItemKind::Union(_, generics, _)
648-
| hir::ItemKind::Trait(_, _, _, _, generics, ..)
648+
| hir::ItemKind::Trait(_, _, _, _, _, generics, ..)
649649
| hir::ItemKind::TraitAlias(_, _, generics, ..)
650650
| hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
651651
// These kinds of items have only early-bound lifetime parameters.

compiler/rustc_hir_analysis/src/errors.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,16 @@ pub(crate) struct SpecializationTrait {
10351035
pub span: Span,
10361036
}
10371037

1038+
#[derive(Diagnostic)]
1039+
#[diag("trait cannot be implemented outside `{$restriction_path}`")]
1040+
pub(crate) struct ImplOfRestrictedTrait {
1041+
#[primary_span]
1042+
pub impl_span: Span,
1043+
#[note("trait restricted here")]
1044+
pub restriction_span: Span,
1045+
pub restriction_path: String,
1046+
}
1047+
10381048
#[derive(Diagnostic)]
10391049
#[diag("implicit types in closure signatures are forbidden when `for<...>` is present")]
10401050
pub(crate) struct ClosureImplicitHrtb {

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ impl<'a> State<'a> {
761761
constness,
762762
is_auto,
763763
safety,
764+
impl_restriction,
764765
ident,
765766
generics,
766767
bounds,
@@ -770,6 +771,7 @@ impl<'a> State<'a> {
770771
self.print_constness(constness);
771772
self.print_is_auto(is_auto);
772773
self.print_safety(safety);
774+
self.print_impl_restriction(impl_restriction);
773775
self.word_nbsp("trait");
774776
self.print_ident(ident);
775777
self.print_generic_params(generics.params);
@@ -2645,6 +2647,18 @@ impl<'a> State<'a> {
26452647
hir::IsAuto::No => {}
26462648
}
26472649
}
2650+
2651+
fn print_impl_restriction(&mut self, r: &hir::ImplRestriction<'_>) {
2652+
match r.kind {
2653+
hir::RestrictionKind::Unrestricted => {}
2654+
hir::RestrictionKind::Restricted(path) => {
2655+
self.word("impl(");
2656+
self.word_nbsp("in");
2657+
self.print_path(path, false);
2658+
self.word(")");
2659+
}
2660+
}
2661+
}
26482662
}
26492663

26502664
/// Does this expression require a semicolon to be treated

compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,7 +1898,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
18981898
Some(
18991899
Node::Item(hir::Item {
19001900
kind:
1901-
hir::ItemKind::Trait(_, _, _, ident, ..)
1901+
hir::ItemKind::Trait(_, _, _, _, ident, ..)
19021902
| hir::ItemKind::TraitAlias(_, ident, ..),
19031903
..
19041904
})
@@ -4545,7 +4545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
45454545
return;
45464546
}
45474547
Node::Item(hir::Item {
4548-
kind: hir::ItemKind::Trait(_, _, _, ident, _, bounds, _),
4548+
kind: hir::ItemKind::Trait(_, _, _, _, ident, _, bounds, _),
45494549
..
45504550
}) => {
45514551
let (sp, sep, article) = if bounds.is_empty() {

0 commit comments

Comments
 (0)