@@ -187,48 +187,63 @@ fn compare_method_predicate_entailment<'tcx>(
187187 let impl_to_placeholder_args = GenericArgs :: identity_for_item ( tcx, impl_m. def_id ) ;
188188
189189 // Create mapping from trait to placeholder.
190+ let impl_def_id = impl_m. container_id ( tcx) ;
190191 let trait_to_placeholder_args =
191- impl_to_placeholder_args. rebase_onto ( tcx, impl_m . container_id ( tcx ) , trait_to_impl_args) ;
192+ impl_to_placeholder_args. rebase_onto ( tcx, impl_def_id , trait_to_impl_args) ;
192193 debug ! ( "compare_impl_method: trait_to_placeholder_args={:?}" , trait_to_placeholder_args) ;
193194
194195 let impl_m_predicates = tcx. predicates_of ( impl_m. def_id ) ;
195196 let trait_m_predicates = tcx. predicates_of ( trait_m. def_id ) ;
196197
197- // Create obligations for each predicate declared by the impl
198- // definition in the context of the trait's parameter
199- // environment. We can't just use `impl_env.caller_bounds`,
200- // however, because we want to replace all late-bound regions with
201- // region variables.
202- let impl_predicates = tcx. predicates_of ( impl_m_predicates. parent . unwrap ( ) ) ;
203- let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) ;
204-
205- debug ! ( "compare_impl_method: impl_bounds={:?}" , hybrid_preds) ;
206-
207198 // This is the only tricky bit of the new way we check implementation methods
208199 // We need to build a set of predicates where only the method-level bounds
209200 // are from the trait and we assume all other bounds from the implementation
210201 // to be previously satisfied.
211202 //
212203 // We then register the obligations from the impl_m and check to see
213204 // if all constraints hold.
214- hybrid_preds. predicates . extend (
205+ let impl_predicates = tcx. predicates_of ( impl_m_predicates. parent . unwrap ( ) ) ;
206+ let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) . predicates ;
207+ hybrid_preds. extend (
215208 trait_m_predicates
216209 . instantiate_own ( tcx, trait_to_placeholder_args)
217210 . map ( |( predicate, _) | predicate) ,
218211 ) ;
219212
213+ // FIXME(effects): This should be replaced with a more dedicated method.
214+ let check_const_if_const = tcx. constness ( impl_def_id) == hir:: Constness :: Const ;
215+ if check_const_if_const {
216+ // Augment the hybrid param-env with the const conditions.
217+ hybrid_preds. extend (
218+ tcx. const_conditions ( impl_def_id)
219+ . instantiate_identity ( tcx)
220+ . into_iter ( )
221+ . chain (
222+ tcx. const_conditions ( trait_m. def_id )
223+ . instantiate_own ( tcx, trait_to_placeholder_args) ,
224+ )
225+ . map ( |( trait_ref, _) | {
226+ trait_ref. to_host_effect_clause ( tcx, ty:: HostPolarity :: Maybe )
227+ } ) ,
228+ ) ;
229+ }
230+
220231 // Construct trait parameter environment and then shift it into the placeholder viewpoint.
221232 // The key step here is to update the caller_bounds's predicates to be
222233 // the new hybrid bounds we computed.
223234 let normalize_cause = traits:: ObligationCause :: misc ( impl_m_span, impl_m_def_id) ;
224- let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds. predicates ) , Reveal :: UserFacing ) ;
235+ let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds) , Reveal :: UserFacing ) ;
225236 let param_env = traits:: normalize_param_env_or_error ( tcx, param_env, normalize_cause) ;
226237
227238 let infcx = & tcx. infer_ctxt ( ) . build ( ) ;
228239 let ocx = ObligationCtxt :: new_with_diagnostics ( infcx) ;
229240
230241 debug ! ( "compare_impl_method: caller_bounds={:?}" , param_env. caller_bounds( ) ) ;
231242
243+ // Create obligations for each predicate declared by the impl
244+ // definition in the context of the hybrid param-env. This makes
245+ // sure that the impl's method's where clauses are not more
246+ // restrictive than the trait's method (and the impl itself).
232247 let impl_m_own_bounds = impl_m_predicates. instantiate_own ( tcx, impl_to_placeholder_args) ;
233248 for ( predicate, span) in impl_m_own_bounds {
234249 let normalize_cause = traits:: ObligationCause :: misc ( span, impl_m_def_id) ;
@@ -243,6 +258,34 @@ fn compare_method_predicate_entailment<'tcx>(
243258 ocx. register_obligation ( traits:: Obligation :: new ( tcx, cause, param_env, predicate) ) ;
244259 }
245260
261+ // If we're within a const implementation, we need to make sure that the method
262+ // does not assume stronger `~const` bounds than the trait definition.
263+ //
264+ // This registers the `~const` bounds of the impl method, which we will prove
265+ // using the hybrid param-env that we earlier augmented with the const conditions
266+ // from the impl header and trait method declaration.
267+ if check_const_if_const {
268+ for ( const_condition, span) in
269+ tcx. const_conditions ( impl_m. def_id ) . instantiate_own ( tcx, impl_to_placeholder_args)
270+ {
271+ let normalize_cause = traits:: ObligationCause :: misc ( span, impl_m_def_id) ;
272+ let const_condition = ocx. normalize ( & normalize_cause, param_env, const_condition) ;
273+
274+ let cause =
275+ ObligationCause :: new ( span, impl_m_def_id, ObligationCauseCode :: CompareImplItem {
276+ impl_item_def_id : impl_m_def_id,
277+ trait_item_def_id : trait_m. def_id ,
278+ kind : impl_m. kind ,
279+ } ) ;
280+ ocx. register_obligation ( traits:: Obligation :: new (
281+ tcx,
282+ cause,
283+ param_env,
284+ const_condition. to_host_effect_clause ( tcx, ty:: HostPolarity :: Maybe ) ,
285+ ) ) ;
286+ }
287+ }
288+
246289 // We now need to check that the signature of the impl method is
247290 // compatible with that of the trait method. We do this by
248291 // checking that `impl_fty <: trait_fty`.
@@ -1759,14 +1802,14 @@ fn compare_const_predicate_entailment<'tcx>(
17591802 // The predicates declared by the impl definition, the trait and the
17601803 // associated const in the trait are assumed.
17611804 let impl_predicates = tcx. predicates_of ( impl_ct_predicates. parent . unwrap ( ) ) ;
1762- let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) ;
1763- hybrid_preds. predicates . extend (
1805+ let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) . predicates ;
1806+ hybrid_preds. extend (
17641807 trait_ct_predicates
17651808 . instantiate_own ( tcx, trait_to_impl_args)
17661809 . map ( |( predicate, _) | predicate) ,
17671810 ) ;
17681811
1769- let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds. predicates ) , Reveal :: UserFacing ) ;
1812+ let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds) , Reveal :: UserFacing ) ;
17701813 let param_env = traits:: normalize_param_env_or_error (
17711814 tcx,
17721815 param_env,
@@ -1871,14 +1914,16 @@ fn compare_type_predicate_entailment<'tcx>(
18711914 impl_trait_ref : ty:: TraitRef < ' tcx > ,
18721915) -> Result < ( ) , ErrorGuaranteed > {
18731916 let impl_args = GenericArgs :: identity_for_item ( tcx, impl_ty. def_id ) ;
1874- let trait_to_impl_args =
1875- impl_args. rebase_onto ( tcx, impl_ty . container_id ( tcx ) , impl_trait_ref. args ) ;
1917+ let impl_def_id = impl_ty . container_id ( tcx ) ;
1918+ let trait_to_impl_args = impl_args. rebase_onto ( tcx, impl_def_id , impl_trait_ref. args ) ;
18761919
18771920 let impl_ty_predicates = tcx. predicates_of ( impl_ty. def_id ) ;
18781921 let trait_ty_predicates = tcx. predicates_of ( trait_ty. def_id ) ;
18791922
18801923 let impl_ty_own_bounds = impl_ty_predicates. instantiate_own ( tcx, impl_args) ;
1881- if impl_ty_own_bounds. len ( ) == 0 {
1924+ let impl_ty_own_const_conditions =
1925+ tcx. const_conditions ( impl_ty. def_id ) . instantiate_own ( tcx, impl_args) ;
1926+ if impl_ty_own_bounds. len ( ) == 0 && impl_ty_own_const_conditions. len ( ) == 0 {
18821927 // Nothing to check.
18831928 return Ok ( ( ) ) ;
18841929 }
@@ -1892,18 +1937,33 @@ fn compare_type_predicate_entailment<'tcx>(
18921937 // The predicates declared by the impl definition, the trait and the
18931938 // associated type in the trait are assumed.
18941939 let impl_predicates = tcx. predicates_of ( impl_ty_predicates. parent . unwrap ( ) ) ;
1895- let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) ;
1896- hybrid_preds. predicates . extend (
1940+ let mut hybrid_preds = impl_predicates. instantiate_identity ( tcx) . predicates ;
1941+ hybrid_preds. extend (
18971942 trait_ty_predicates
18981943 . instantiate_own ( tcx, trait_to_impl_args)
18991944 . map ( |( predicate, _) | predicate) ,
19001945 ) ;
19011946
1947+ let check_const_if_const = tcx. constness ( impl_def_id) == hir:: Constness :: Const ;
1948+ if check_const_if_const {
1949+ hybrid_preds. extend (
1950+ tcx. const_conditions ( impl_ty_predicates. parent . unwrap ( ) )
1951+ . instantiate_identity ( tcx)
1952+ . into_iter ( )
1953+ . chain (
1954+ tcx. const_conditions ( trait_ty. def_id ) . instantiate_own ( tcx, trait_to_impl_args) ,
1955+ )
1956+ . map ( |( trait_ref, _) | {
1957+ trait_ref. to_host_effect_clause ( tcx, ty:: HostPolarity :: Maybe )
1958+ } ) ,
1959+ ) ;
1960+ }
1961+
19021962 debug ! ( "compare_type_predicate_entailment: bounds={:?}" , hybrid_preds) ;
19031963
19041964 let impl_ty_span = tcx. def_span ( impl_ty_def_id) ;
19051965 let normalize_cause = ObligationCause :: misc ( impl_ty_span, impl_ty_def_id) ;
1906- let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds. predicates ) , Reveal :: UserFacing ) ;
1966+ let param_env = ty:: ParamEnv :: new ( tcx. mk_clauses ( & hybrid_preds) , Reveal :: UserFacing ) ;
19071967 let param_env = traits:: normalize_param_env_or_error ( tcx, param_env, normalize_cause) ;
19081968 let infcx = tcx. infer_ctxt ( ) . build ( ) ;
19091969 let ocx = ObligationCtxt :: new_with_diagnostics ( & infcx) ;
@@ -1923,6 +1983,27 @@ fn compare_type_predicate_entailment<'tcx>(
19231983 ocx. register_obligation ( traits:: Obligation :: new ( tcx, cause, param_env, predicate) ) ;
19241984 }
19251985
1986+ if check_const_if_const {
1987+ // Validate the const conditions of the impl method.
1988+ for ( const_condition, span) in impl_ty_own_const_conditions {
1989+ let normalize_cause = traits:: ObligationCause :: misc ( span, impl_ty_def_id) ;
1990+ let const_condition = ocx. normalize ( & normalize_cause, param_env, const_condition) ;
1991+
1992+ let cause =
1993+ ObligationCause :: new ( span, impl_ty_def_id, ObligationCauseCode :: CompareImplItem {
1994+ impl_item_def_id : impl_ty_def_id,
1995+ trait_item_def_id : trait_ty. def_id ,
1996+ kind : impl_ty. kind ,
1997+ } ) ;
1998+ ocx. register_obligation ( traits:: Obligation :: new (
1999+ tcx,
2000+ cause,
2001+ param_env,
2002+ const_condition. to_host_effect_clause ( tcx, ty:: HostPolarity :: Maybe ) ,
2003+ ) ) ;
2004+ }
2005+ }
2006+
19262007 // Check that all obligations are satisfied by the implementation's
19272008 // version.
19282009 let errors = ocx. select_all_or_error ( ) ;
@@ -2005,14 +2086,30 @@ pub(super) fn check_type_bounds<'tcx>(
20052086 ObligationCause :: new ( impl_ty_span, impl_ty_def_id, code)
20062087 } ;
20072088
2008- let obligations: Vec < _ > = tcx
2089+ let mut obligations: Vec < _ > = tcx
20092090 . explicit_item_bounds ( trait_ty. def_id )
20102091 . iter_instantiated_copied ( tcx, rebased_args)
20112092 . map ( |( concrete_ty_bound, span) | {
20122093 debug ! ( "check_type_bounds: concrete_ty_bound = {:?}" , concrete_ty_bound) ;
20132094 traits:: Obligation :: new ( tcx, mk_cause ( span) , param_env, concrete_ty_bound)
20142095 } )
20152096 . collect ( ) ;
2097+
2098+ // Only in a const implementation do we need to check that the `~const` item bounds hold.
2099+ if tcx. constness ( container_id) == hir:: Constness :: Const {
2100+ obligations. extend (
2101+ tcx. implied_const_bounds ( trait_ty. def_id )
2102+ . iter_instantiated_copied ( tcx, rebased_args)
2103+ . map ( |( c, span) | {
2104+ traits:: Obligation :: new (
2105+ tcx,
2106+ mk_cause ( span) ,
2107+ param_env,
2108+ c. to_host_effect_clause ( tcx, ty:: HostPolarity :: Maybe ) ,
2109+ )
2110+ } ) ,
2111+ ) ;
2112+ }
20162113 debug ! ( "check_type_bounds: item_bounds={:?}" , obligations) ;
20172114
20182115 // Normalize predicates with the assumption that the GAT may always normalize
0 commit comments