Skip to content

Commit 8c39028

Browse files
committed
Type-check generic const items
1 parent da17134 commit 8c39028

File tree

4 files changed

+122
-103
lines changed

4 files changed

+122
-103
lines changed

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ fn check_method_is_structurally_compatible<'tcx>(
7676
Ok(())
7777
}
7878

79-
/// This function is best explained by example. Consider a trait with it's implementation:
79+
/// This function is best explained by example. Consider a trait with its implementation:
8080
///
8181
/// ```rust
8282
/// trait Trait<'t, T> {
@@ -120,7 +120,7 @@ fn check_method_is_structurally_compatible<'tcx>(
120120
/// types:
121121
///
122122
/// ```rust,ignore (pseudo-Rust)
123-
/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
123+
/// <'b> fn(t: &'i0 U0, m: &'b N0) -> Foo
124124
/// ```
125125
///
126126
/// We now want to extract and substitute the type of the *trait*
@@ -137,7 +137,7 @@ fn check_method_is_structurally_compatible<'tcx>(
137137
/// Applying this to the trait method type yields:
138138
///
139139
/// ```rust,ignore (pseudo-Rust)
140-
/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
140+
/// <'a> fn(t: &'i0 U0, m: &'a N0) -> Foo
141141
/// ```
142142
///
143143
/// This type is also the same but the name of the bound region (`'a`
@@ -258,8 +258,6 @@ fn compare_method_predicate_entailment<'tcx>(
258258
// type.
259259

260260
// Compute placeholder form of impl and trait method tys.
261-
let tcx = infcx.tcx;
262-
263261
let mut wf_tys = FxIndexSet::default();
264262

265263
let unnormalized_impl_sig = infcx.instantiate_binder_with_fresh_vars(
@@ -1668,19 +1666,19 @@ fn compare_synthetic_generics<'tcx>(
16681666
/// ```rust,ignore (pseudo-Rust)
16691667
/// trait Foo {
16701668
/// fn foo<const N: u8>();
1671-
/// type bar<const N: u8>;
1669+
/// type Bar<const N: u8>;
16721670
/// fn baz<const N: u32>();
1673-
/// type blah<T>;
1671+
/// type Blah<T>;
16741672
/// }
16751673
///
16761674
/// impl Foo for () {
16771675
/// fn foo<const N: u64>() {}
16781676
/// //~^ error
1679-
/// type bar<const N: u64> {}
1677+
/// type Bar<const N: u64> = ();
16801678
/// //~^ error
16811679
/// fn baz<T>() {}
16821680
/// //~^ error
1683-
/// type blah<const N: i64> = u32;
1681+
/// type Blah<const N: i64> = u32;
16841682
/// //~^ error
16851683
/// }
16861684
/// ```
@@ -1769,36 +1767,82 @@ pub(super) fn compare_impl_const_raw(
17691767
let trait_const_item = tcx.associated_item(trait_const_item_def);
17701768
let impl_trait_ref =
17711769
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
1772-
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
17731770

1774-
let impl_c_span = tcx.def_span(impl_const_item_def.to_def_id());
1771+
debug!("compare_impl_const(impl_trait_ref={:?})", impl_trait_ref);
17751772

1776-
let infcx = tcx.infer_ctxt().build();
1777-
let param_env = tcx.param_env(impl_const_item_def.to_def_id());
1778-
let ocx = ObligationCtxt::new(&infcx);
1773+
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
1774+
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
1775+
compare_const_predicate_entailment(tcx, impl_const_item, trait_const_item, impl_trait_ref)
1776+
}
1777+
1778+
/// The equivalent of [compare_method_predicate_entailment], but for associated constants
1779+
/// instead of associated functions.
1780+
// FIXME(generic_const_items): If possible extract the common parts of `compare_{type,const}_predicate_entailment`.
1781+
fn compare_const_predicate_entailment<'tcx>(
1782+
tcx: TyCtxt<'tcx>,
1783+
impl_ct: ty::AssocItem,
1784+
trait_ct: ty::AssocItem,
1785+
impl_trait_ref: ty::TraitRef<'tcx>,
1786+
) -> Result<(), ErrorGuaranteed> {
1787+
let impl_ct_def_id = impl_ct.def_id.expect_local();
1788+
let impl_ct_span = tcx.def_span(impl_ct_def_id);
17791789

17801790
// The below is for the most part highly similar to the procedure
17811791
// for methods above. It is simpler in many respects, especially
17821792
// because we shouldn't really have to deal with lifetimes or
17831793
// predicates. In fact some of this should probably be put into
17841794
// shared functions because of DRY violations...
1785-
let trait_to_impl_args = impl_trait_ref.args;
1795+
let impl_args = GenericArgs::identity_for_item(tcx, impl_ct.def_id);
1796+
let trait_to_impl_args =
1797+
impl_args.rebase_onto(tcx, impl_ct.container_id(tcx), impl_trait_ref.args);
17861798

17871799
// Create a parameter environment that represents the implementation's
17881800
// method.
17891801
// Compute placeholder form of impl and trait const tys.
1790-
let impl_ty = tcx.type_of(impl_const_item_def.to_def_id()).instantiate_identity();
1791-
let trait_ty = tcx.type_of(trait_const_item_def).instantiate(tcx, trait_to_impl_args);
1792-
let mut cause = ObligationCause::new(
1793-
impl_c_span,
1794-
impl_const_item_def,
1795-
ObligationCauseCode::CompareImplItemObligation {
1796-
impl_item_def_id: impl_const_item_def,
1797-
trait_item_def_id: trait_const_item_def,
1798-
kind: impl_const_item.kind,
1799-
},
1802+
let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
1803+
1804+
let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
1805+
let code = ObligationCauseCode::CompareImplItemObligation {
1806+
impl_item_def_id: impl_ct_def_id,
1807+
trait_item_def_id: trait_ct.def_id,
1808+
kind: impl_ct.kind,
1809+
};
1810+
let mut cause = ObligationCause::new(impl_ct_span, impl_ct_def_id, code.clone());
1811+
1812+
let impl_ct_predicates = tcx.predicates_of(impl_ct.def_id);
1813+
let trait_ct_predicates = tcx.predicates_of(trait_ct.def_id);
1814+
1815+
check_region_bounds_on_impl_item(tcx, impl_ct, trait_ct, false)?;
1816+
1817+
// The predicates declared by the impl definition, the trait and the
1818+
// associated const in the trait are assumed.
1819+
let impl_predicates = tcx.predicates_of(impl_ct_predicates.parent.unwrap());
1820+
let mut hybrid_preds = impl_predicates.instantiate_identity(tcx);
1821+
hybrid_preds.predicates.extend(
1822+
trait_ct_predicates
1823+
.instantiate_own(tcx, trait_to_impl_args)
1824+
.map(|(predicate, _)| predicate),
1825+
);
1826+
1827+
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
1828+
let param_env = traits::normalize_param_env_or_error(
1829+
tcx,
1830+
param_env,
1831+
ObligationCause::misc(impl_ct_span, impl_ct_def_id),
18001832
);
18011833

1834+
let infcx = tcx.infer_ctxt().build();
1835+
let ocx = ObligationCtxt::new(&infcx);
1836+
1837+
let impl_ct_own_bounds = impl_ct_predicates.instantiate_own(tcx, impl_args);
1838+
for (predicate, span) in impl_ct_own_bounds {
1839+
let cause = ObligationCause::misc(span, impl_ct_def_id);
1840+
let predicate = ocx.normalize(&cause, param_env, predicate);
1841+
1842+
let cause = ObligationCause::new(span, impl_ct_def_id, code.clone());
1843+
ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, predicate));
1844+
}
1845+
18021846
// There is no "body" here, so just pass dummy id.
18031847
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
18041848

@@ -1817,20 +1861,20 @@ pub(super) fn compare_impl_const_raw(
18171861
);
18181862

18191863
// Locate the Span containing just the type of the offending impl
1820-
let (ty, _) = tcx.hir().expect_impl_item(impl_const_item_def).expect_const();
1864+
let (ty, _) = tcx.hir().expect_impl_item(impl_ct_def_id).expect_const();
18211865
cause.span = ty.span;
18221866

18231867
let mut diag = struct_span_err!(
18241868
tcx.sess,
18251869
cause.span,
18261870
E0326,
18271871
"implemented const `{}` has an incompatible type for trait",
1828-
trait_const_item.name
1872+
trait_ct.name
18291873
);
18301874

1831-
let trait_c_span = trait_const_item_def.as_local().map(|trait_c_def_id| {
1875+
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
18321876
// Add a label to the Span containing just the type of the const
1833-
let (ty, _) = tcx.hir().expect_trait_item(trait_c_def_id).expect_const();
1877+
let (ty, _) = tcx.hir().expect_trait_item(trait_ct_def_id).expect_const();
18341878
ty.span
18351879
});
18361880

@@ -1857,7 +1901,7 @@ pub(super) fn compare_impl_const_raw(
18571901
}
18581902

18591903
let outlives_env = OutlivesEnvironment::new(param_env);
1860-
ocx.resolve_regions_and_report_errors(impl_const_item_def, &outlives_env)
1904+
ocx.resolve_regions_and_report_errors(impl_ct_def_id, &outlives_env)
18611905
}
18621906

18631907
pub(super) fn compare_impl_ty<'tcx>(
@@ -1899,7 +1943,7 @@ fn compare_type_predicate_entailment<'tcx>(
18991943
return Ok(());
19001944
}
19011945

1902-
// This `HirId` should be used for the `body_id` field on each
1946+
// This `DefId` should be used for the `body_id` field on each
19031947
// `ObligationCause` (and the `FnCtxt`). This is what
19041948
// `regionck_item` expects.
19051949
let impl_ty_def_id = impl_ty.def_id.expect_local();
@@ -1918,7 +1962,7 @@ fn compare_type_predicate_entailment<'tcx>(
19181962
debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds);
19191963

19201964
let impl_ty_span = tcx.def_span(impl_ty_def_id);
1921-
let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_def_id);
1965+
let normalize_cause = ObligationCause::misc(impl_ty_span, impl_ty_def_id);
19221966
let param_env = ty::ParamEnv::new(tcx.mk_clauses(&hybrid_preds.predicates), Reveal::UserFacing);
19231967
let param_env = traits::normalize_param_env_or_error(tcx, param_env, normalize_cause);
19241968
let infcx = tcx.infer_ctxt().build();
@@ -1963,7 +2007,7 @@ fn compare_type_predicate_entailment<'tcx>(
19632007
///
19642008
/// trait X { type Y: Copy } impl X for T { type Y = S; }
19652009
///
1966-
/// We are able to normalize `<T as X>::U` to `S`, and so when we check the
2010+
/// We are able to normalize `<T as X>::Y` to `S`, and so when we check the
19672011
/// impl is well-formed we have to prove `S: Copy`.
19682012
///
19692013
/// For default associated types the normalization is not possible (the value

compiler/rustc_hir_analysis/src/collect/generics_of.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
209209
| ItemKind::Struct(..)
210210
| ItemKind::OpaqueTy(..)
211211
| ItemKind::Union(..) => (None, Defaults::Allowed),
212+
ItemKind::Const(..) => (None, Defaults::Deny),
212213
_ => (None, Defaults::FutureCompatDisallowed),
213214
}
214215
}

compiler/rustc_hir_analysis/src/collect/predicates_of.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
156156
}
157157
ItemKind::Fn(.., generics, _)
158158
| ItemKind::TyAlias(_, generics)
159+
| ItemKind::Const(_, generics, _)
159160
| ItemKind::Enum(_, generics)
160161
| ItemKind::Struct(_, generics)
161162
| ItemKind::Union(_, generics) => generics,
@@ -762,6 +763,7 @@ pub(super) fn type_param_predicates(
762763
ItemKind::Fn(.., generics, _)
763764
| ItemKind::Impl(&hir::Impl { generics, .. })
764765
| ItemKind::TyAlias(_, generics)
766+
| ItemKind::Const(_, generics, _)
765767
| ItemKind::OpaqueTy(&OpaqueTy {
766768
generics,
767769
origin: hir::OpaqueTyOrigin::TyAlias { .. },

0 commit comments

Comments
 (0)