@@ -8,10 +8,8 @@ use rustc_infer::infer::TyCtxtInferExt;
88use rustc_infer:: traits:: { ImplSource , Obligation , ObligationCause } ;
99use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
1010use rustc_middle:: mir:: * ;
11- use rustc_middle:: traits:: BuiltinImplSource ;
12- use rustc_middle:: ty:: GenericArgs ;
13- use rustc_middle:: ty:: { self , adjustment:: PointerCoercion , Instance , InstanceDef , Ty , TyCtxt } ;
14- use rustc_middle:: ty:: { TraitRef , TypeVisitableExt } ;
11+ use rustc_middle:: ty:: { self , adjustment:: PointerCoercion , Ty , TyCtxt } ;
12+ use rustc_middle:: ty:: { GenericArgs , Instance , InstanceDef , TraitRef , TypeVisitableExt } ;
1513use rustc_mir_dataflow:: Analysis ;
1614use rustc_span:: { sym, Span , Symbol } ;
1715use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt as _;
@@ -752,142 +750,61 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
752750 infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
753751 }
754752
753+ let mut is_trait = false ;
755754 // Attempting to call a trait method?
756- // FIXME(effects) do we need this?
757755 if let Some ( trait_id) = tcx. trait_of_item ( callee) {
758756 trace ! ( "attempting to call a trait method" ) ;
759- if !self . tcx . features ( ) . const_trait_impl {
760- self . check_op ( ops:: FnCallNonConst {
761- caller,
762- callee,
763- args : fn_args,
764- span : * fn_span,
765- call_source : * call_source,
766- feature : Some ( sym:: const_trait_impl) ,
767- } ) ;
768- return ;
769- }
770-
771- let trait_ref = TraitRef :: from_method ( tcx, trait_id, fn_args) ;
772- let obligation =
773- Obligation :: new ( tcx, ObligationCause :: dummy ( ) , param_env, trait_ref) ;
774-
775- let implsrc = {
776- let infcx = tcx. infer_ctxt ( ) . build ( ) ;
777- let mut selcx = SelectionContext :: new ( & infcx) ;
778- selcx. select ( & obligation)
779- } ;
780-
781- match implsrc {
782- Ok ( Some ( ImplSource :: Param ( _) ) ) if tcx. features ( ) . effects => {
783- debug ! (
784- "const_trait_impl: provided {:?} via where-clause in {:?}" ,
785- trait_ref, param_env
786- ) ;
787- return ;
788- }
789- // Closure: Fn{Once|Mut}
790- Ok ( Some ( ImplSource :: Builtin ( BuiltinImplSource :: Misc , _) ) )
791- if trait_ref. self_ty ( ) . is_closure ( )
792- && tcx. fn_trait_kind_from_def_id ( trait_id) . is_some ( ) =>
793- {
794- let ty:: Closure ( closure_def_id, fn_args) = * trait_ref. self_ty ( ) . kind ( )
795- else {
796- unreachable ! ( )
797- } ;
798- if !tcx. is_const_fn_raw ( closure_def_id) {
799- self . check_op ( ops:: FnCallNonConst {
800- caller,
801- callee,
802- args : fn_args,
803- span : * fn_span,
804- call_source : * call_source,
805- feature : None ,
806- } ) ;
807-
808- return ;
809- }
810- }
811- Ok ( Some ( ImplSource :: UserDefined ( data) ) ) => {
757+ // trait method calls are only permitted when `effects` is enabled.
758+ // we don't error, since that is handled by typeck. We try to resolve
759+ // the trait into the concrete method, and uses that for const stability
760+ // checks.
761+ // FIXME(effects) we might consider moving const stability checks to typeck as well.
762+ if tcx. features ( ) . effects {
763+ is_trait = true ;
764+ let trait_ref = TraitRef :: from_method ( tcx, trait_id, fn_args) ;
765+ let obligation =
766+ Obligation :: new ( tcx, ObligationCause :: dummy ( ) , param_env, trait_ref) ;
767+
768+ let implsrc = {
769+ let infcx = tcx. infer_ctxt ( ) . build ( ) ;
770+ let mut selcx = SelectionContext :: new ( & infcx) ;
771+ selcx. select ( & obligation)
772+ } ;
773+ if let Ok ( Some ( ImplSource :: UserDefined ( data) ) ) = implsrc {
812774 let callee_name = tcx. item_name ( callee) ;
813775
814- if let hir:: Constness :: NotConst = tcx. constness ( data. impl_def_id ) {
815- self . check_op ( ops:: FnCallNonConst {
816- caller,
817- callee,
818- args : fn_args,
819- span : * fn_span,
820- call_source : * call_source,
821- feature : None ,
822- } ) ;
823- return ;
824- }
825-
826776 if let Some ( & did) = tcx
827777 . associated_item_def_ids ( data. impl_def_id )
828778 . iter ( )
829779 . find ( |did| tcx. item_name ( * * did) == callee_name)
830780 {
831- // using internal args is ok here, since this is only
832- // used for the `resolve` call below
833781 fn_args = GenericArgs :: identity_for_item ( tcx, did) ;
834782 callee = did;
835- }
836- }
837- _ if !tcx. is_const_fn_raw ( callee) => {
838- // At this point, it is only legal when the caller is in a trait
839- // marked with #[const_trait], and the callee is in the same trait.
840- let mut nonconst_call_permission = false ;
841- if let Some ( callee_trait) = tcx. trait_of_item ( callee)
842- && tcx. has_attr ( callee_trait, sym:: const_trait)
843- && Some ( callee_trait) == tcx. trait_of_item ( caller. to_def_id ( ) )
844- // Can only call methods when it's `<Self as TheTrait>::f`.
845- && tcx. types . self_param == fn_args. type_at ( 0 )
846- {
847- nonconst_call_permission = true ;
848- }
849-
850- if !nonconst_call_permission {
851- let obligation = Obligation :: new (
852- tcx,
853- ObligationCause :: dummy_with_span ( * fn_span) ,
854- param_env,
855- trait_ref,
856- ) ;
857-
858- // improve diagnostics by showing what failed. Our requirements are stricter this time
859- // as we are going to error again anyways.
860- let infcx = tcx. infer_ctxt ( ) . build ( ) ;
861- if let Err ( e) = implsrc {
862- infcx. err_ctxt ( ) . report_selection_error (
863- obligation. clone ( ) ,
864- & obligation,
865- & e,
866- ) ;
783+ // Resolve a trait method call to its concrete implementation, which may be in a
784+ // `const` trait impl.
785+ let instance = Instance :: resolve ( tcx, param_env, callee, fn_args) ;
786+ debug ! ( "Resolving ({:?}) -> {:?}" , callee, instance) ;
787+ if let Ok ( Some ( func) ) = instance {
788+ if let InstanceDef :: Item ( def) = func. def {
789+ callee = def;
790+ }
867791 }
868-
869- self . check_op ( ops:: FnCallNonConst {
870- caller,
871- callee,
872- args : fn_args,
873- span : * fn_span,
874- call_source : * call_source,
875- feature : None ,
876- } ) ;
877- return ;
878792 }
879793 }
880- _ => { }
881- }
882-
883- // Resolve a trait method call to its concrete implementation, which may be in a
884- // `const` trait impl.
885- let instance = Instance :: resolve ( tcx, param_env, callee, fn_args) ;
886- debug ! ( "Resolving ({:?}) -> {:?}" , callee, instance) ;
887- if let Ok ( Some ( func) ) = instance {
888- if let InstanceDef :: Item ( def) = func. def {
889- callee = def;
890- }
794+ } else {
795+ self . check_op ( ops:: FnCallNonConst {
796+ caller,
797+ callee,
798+ args : fn_args,
799+ span : * fn_span,
800+ call_source : * call_source,
801+ feature : Some ( if tcx. features ( ) . const_trait_impl {
802+ sym:: effects
803+ } else {
804+ sym:: const_trait_impl
805+ } ) ,
806+ } ) ;
807+ return ;
891808 }
892809 }
893810
@@ -921,21 +838,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
921838 return ;
922839 }
923840
924- if !tcx. is_const_fn_raw ( callee) {
925- if !tcx. is_const_default_method ( callee) {
926- // To get to here we must have already found a const impl for the
927- // trait, but for it to still be non-const can be that the impl is
928- // using default method bodies.
929- self . check_op ( ops:: FnCallNonConst {
930- caller,
931- callee,
932- args : fn_args,
933- span : * fn_span,
934- call_source : * call_source,
935- feature : None ,
936- } ) ;
937- return ;
938- }
841+ if !tcx. is_const_fn_raw ( callee) && !is_trait {
842+ self . check_op ( ops:: FnCallNonConst {
843+ caller,
844+ callee,
845+ args : fn_args,
846+ span : * fn_span,
847+ call_source : * call_source,
848+ feature : None ,
849+ } ) ;
850+ return ;
939851 }
940852
941853 // If the `const fn` we are trying to call is not const-stable, ensure that we have
0 commit comments