@@ -5,17 +5,15 @@ use rustc_hir as hir;
55use rustc_hir:: def_id:: DefId ;
66use rustc_index:: bit_set:: BitSet ;
77use rustc_infer:: infer:: TyCtxtInferExt ;
8- use rustc_infer:: traits:: { ImplSource , Obligation , ObligationCause } ;
8+ use rustc_infer:: traits:: 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:: { Instance , InstanceDef , TypeVisitableExt } ;
1513use rustc_mir_dataflow:: Analysis ;
1614use rustc_span:: { sym, Span , Symbol } ;
1715use rustc_trait_selection:: traits:: error_reporting:: TypeErrCtxtExt as _;
18- use rustc_trait_selection:: traits:: { self , ObligationCauseCode , ObligationCtxt , SelectionContext } ;
16+ use rustc_trait_selection:: traits:: { self , ObligationCauseCode , ObligationCtxt } ;
1917use rustc_type_ir:: visit:: { TypeSuperVisitable , TypeVisitor } ;
2018
2119use std:: mem;
@@ -756,143 +754,43 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
756754 infcx. err_ctxt ( ) . report_fulfillment_errors ( errors) ;
757755 }
758756
757+ let mut is_trait = false ;
759758 // Attempting to call a trait method?
760- // FIXME(effects) do we need this?
761- if let Some ( trait_id) = tcx. trait_of_item ( callee) {
759+ if tcx. trait_of_item ( callee) . is_some ( ) {
762760 trace ! ( "attempting to call a trait method" ) ;
763- if !self . tcx . features ( ) . const_trait_impl {
761+ // trait method calls are only permitted when `effects` is enabled.
762+ // we don't error, since that is handled by typeck. We try to resolve
763+ // the trait into the concrete method, and uses that for const stability
764+ // checks.
765+ // FIXME(effects) we might consider moving const stability checks to typeck as well.
766+ if tcx. features ( ) . effects {
767+ is_trait = true ;
768+
769+ if let Ok ( Some ( instance) ) =
770+ Instance :: resolve ( tcx, param_env, callee, fn_args)
771+ && let InstanceDef :: Item ( def) = instance. def
772+ {
773+ // Resolve a trait method call to its concrete implementation, which may be in a
774+ // `const` trait impl. This is only used for the const stability check below, since
775+ // we want to look at the concrete impl's stability.
776+ fn_args = instance. args ;
777+ callee = def;
778+ }
779+ } else {
764780 self . check_op ( ops:: FnCallNonConst {
765781 caller,
766782 callee,
767783 args : fn_args,
768784 span : * fn_span,
769785 call_source : * call_source,
770- feature : Some ( sym:: const_trait_impl) ,
786+ feature : Some ( if tcx. features ( ) . const_trait_impl {
787+ sym:: effects
788+ } else {
789+ sym:: const_trait_impl
790+ } ) ,
771791 } ) ;
772792 return ;
773793 }
774-
775- let trait_ref = TraitRef :: from_method ( tcx, trait_id, fn_args) ;
776- let obligation =
777- Obligation :: new ( tcx, ObligationCause :: dummy ( ) , param_env, trait_ref) ;
778-
779- let implsrc = {
780- let infcx = tcx. infer_ctxt ( ) . build ( ) ;
781- let mut selcx = SelectionContext :: new ( & infcx) ;
782- selcx. select ( & obligation)
783- } ;
784-
785- match implsrc {
786- Ok ( Some ( ImplSource :: Param ( _) ) ) if tcx. features ( ) . effects => {
787- debug ! (
788- "const_trait_impl: provided {:?} via where-clause in {:?}" ,
789- trait_ref, param_env
790- ) ;
791- return ;
792- }
793- // Closure: Fn{Once|Mut}
794- Ok ( Some ( ImplSource :: Builtin ( BuiltinImplSource :: Misc , _) ) )
795- if trait_ref. self_ty ( ) . is_closure ( )
796- && tcx. fn_trait_kind_from_def_id ( trait_id) . is_some ( ) =>
797- {
798- let ty:: Closure ( closure_def_id, fn_args) = * trait_ref. self_ty ( ) . kind ( )
799- else {
800- unreachable ! ( )
801- } ;
802- if !tcx. is_const_fn_raw ( closure_def_id) {
803- self . check_op ( ops:: FnCallNonConst {
804- caller,
805- callee,
806- args : fn_args,
807- span : * fn_span,
808- call_source : * call_source,
809- feature : None ,
810- } ) ;
811-
812- return ;
813- }
814- }
815- Ok ( Some ( ImplSource :: UserDefined ( data) ) ) => {
816- let callee_name = tcx. item_name ( callee) ;
817-
818- if let hir:: Constness :: NotConst = tcx. constness ( data. impl_def_id ) {
819- self . check_op ( ops:: FnCallNonConst {
820- caller,
821- callee,
822- args : fn_args,
823- span : * fn_span,
824- call_source : * call_source,
825- feature : None ,
826- } ) ;
827- return ;
828- }
829-
830- if let Some ( & did) = tcx
831- . associated_item_def_ids ( data. impl_def_id )
832- . iter ( )
833- . find ( |did| tcx. item_name ( * * did) == callee_name)
834- {
835- // using internal args is ok here, since this is only
836- // used for the `resolve` call below
837- fn_args = GenericArgs :: identity_for_item ( tcx, did) ;
838- callee = did;
839- }
840- }
841- _ if !tcx. is_const_fn_raw ( callee) => {
842- // At this point, it is only legal when the caller is in a trait
843- // marked with #[const_trait], and the callee is in the same trait.
844- let mut nonconst_call_permission = false ;
845- if let Some ( callee_trait) = tcx. trait_of_item ( callee)
846- && tcx. has_attr ( callee_trait, sym:: const_trait)
847- && Some ( callee_trait) == tcx. trait_of_item ( caller. to_def_id ( ) )
848- // Can only call methods when it's `<Self as TheTrait>::f`.
849- && tcx. types . self_param == fn_args. type_at ( 0 )
850- {
851- nonconst_call_permission = true ;
852- }
853-
854- if !nonconst_call_permission {
855- let obligation = Obligation :: new (
856- tcx,
857- ObligationCause :: dummy_with_span ( * fn_span) ,
858- param_env,
859- trait_ref,
860- ) ;
861-
862- // improve diagnostics by showing what failed. Our requirements are stricter this time
863- // as we are going to error again anyways.
864- let infcx = tcx. infer_ctxt ( ) . build ( ) ;
865- if let Err ( e) = implsrc {
866- infcx. err_ctxt ( ) . report_selection_error (
867- obligation. clone ( ) ,
868- & obligation,
869- & e,
870- ) ;
871- }
872-
873- self . check_op ( ops:: FnCallNonConst {
874- caller,
875- callee,
876- args : fn_args,
877- span : * fn_span,
878- call_source : * call_source,
879- feature : None ,
880- } ) ;
881- return ;
882- }
883- }
884- _ => { }
885- }
886-
887- // Resolve a trait method call to its concrete implementation, which may be in a
888- // `const` trait impl.
889- let instance = Instance :: resolve ( tcx, param_env, callee, fn_args) ;
890- debug ! ( "Resolving ({:?}) -> {:?}" , callee, instance) ;
891- if let Ok ( Some ( func) ) = instance {
892- if let InstanceDef :: Item ( def) = func. def {
893- callee = def;
894- }
895- }
896794 }
897795
898796 // At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -925,21 +823,16 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
925823 return ;
926824 }
927825
928- if !tcx. is_const_fn_raw ( callee) {
929- if !tcx. is_const_default_method ( callee) {
930- // To get to here we must have already found a const impl for the
931- // trait, but for it to still be non-const can be that the impl is
932- // using default method bodies.
933- self . check_op ( ops:: FnCallNonConst {
934- caller,
935- callee,
936- args : fn_args,
937- span : * fn_span,
938- call_source : * call_source,
939- feature : None ,
940- } ) ;
941- return ;
942- }
826+ if !tcx. is_const_fn_raw ( callee) && !is_trait {
827+ self . check_op ( ops:: FnCallNonConst {
828+ caller,
829+ callee,
830+ args : fn_args,
831+ span : * fn_span,
832+ call_source : * call_source,
833+ feature : None ,
834+ } ) ;
835+ return ;
943836 }
944837
945838 // If the `const fn` we are trying to call is not const-stable, ensure that we have
0 commit comments