Then using LSP function go to definition on Foo.foo, it takes me to the class definition but that is rarely where I want to go. Ideally I would like to go to the particular instance which has been elaborated at a particular point or at least I would like to get a list of all the instances and I pick the right one.
I have a custom syntax to define overloaded functions in a bit less verbose way
and I have tried for each defun to call addDeclarationRangesFromSyntax ``Foo.foo stx. However it does not work as I would like and no wonder as declRangeExt stores only one declaration range per declaration name.
importLeanopenLean/--Declare an overloadable function by creating a single-method typeclass.## Example```leandeclfun sin {α} (x : α) : α```This creates a typeclass `Sin` with a single method `sin`. You can then defineoverloads using `defun`:```leandefun sin (x : Float) := x.sindefun sin (x : Float32) := x.sindefun Vector2.sin (u : Vector2) : Vector2 := ⟨u.x.sin, u.y.sin⟩```## Implementation DetailsInternally, `declfun` creates a typeclass and exports its method. For example,`declfun sin {α} (x : α) : α` generates:```leanclass Sin (α : Type) where sin (x : α) : αexport Sin (sin)```-/syntax(docComment)?"declfun"declIdbracketedBinder*":"term:command/--Define an overload for a function declared with `declfun`.## Example```lean-- Simple overloaddefun sin (x : Float) := x.sin-- Member function (automatically creates both the function and the overload instance)defun Vector2.sin (u : Vector2) : Vector2 := ⟨u.x.sin, u.y.sin⟩```## Behavior- For simple names like `sin`, `defun` creates an instance of the corresponding typeclass- For qualified names like `Vector2.sin`, it defines the member function and creates an instance## Implementation Details`defun` generates typeclass instances. For example, `defun sin (x : Float) := x.sin`creates:```leaninstance : Sin Float where sin x := x.sin```-/syntax(docComment)?"defun"declIdbracketedBinder*(":"term)?":="term:commandopenLeanMetaElabParserTermCommandPrettyPrinterinelab_rules:command|`($[$doc:docComment]?declfun$id:ident$bs:bracketedBinder*:$ty:term)=>dolet(clsBinders,funBinders)←runTermElabMfunctx=>doTerm.elabBindersbsfunxs=>doletr←elabTypetyletts←liftM<|xs.mapMinferTypeletts:=ts.pushrletctx':=ctx.filter(func=>ts.any(funx=>x.containsFVarc.fvarId!))letmutclsBinders:Array(TSyntax``bracketedBinder):=#[]letmutfunBinders:Array(TSyntax``bracketedBinder):=#[]forxinctx'++xsdolett←inferTypex>>=Lean.Elab.Term.levelMVarToParamletn←x.fvarId!.getUserNameletty←delabtletid:=mkIdentnmatch←x.fvarId!.getBinderInfowith|.default=>funBinders:=funBinders.push(←`(bracketedBinder|($id:$ty)))|.implicit=>clsBinders:=clsBinders.push(←`(bracketedBinder|($id:$ty)))|.instImplicit=>clsBinders:=clsBinders.push(←`(bracketedBinder|[$ty]))|.strictImplicit=>clsBinders:=clsBinders.push(←`(bracketedBinder|{$id:$ty}))return(clsBinders,funBinders)letclassName:=mkIdent<|id.getId.capitalizeletcmd←`(class$className:ident$clsBinders*where$[$doc:docComment]?$id:ident$funBinders:bracketedBinder*:$ty)elabCommandcmdelabCommand(←`(export$className($id)))openLeanMetaElabCommandTerminelab_rules:command|`($[$doc:docComment]?defun$id:ident$bs:bracketedBinder*$[:$ty:term]?:=$body)=>dorunTermElabMfun_ctx=>doTerm.elabBindersbsfunxs=>dolettype?←ty.mapMelabTypeletbody←elabTermAndSynthesizebodytype?letxs'←xs.filterM(funx=>(·.isExplicit)<$>x.fvarId!.getBinderInfo)letf←mkLambdaFVarsxs'bodyletclassName:=id.getId.getString!.capitalizeletclassName←resolveGlobalConstNoOverload(mkIdent(.mkSimpleclassName))letinst←mkAppM(className.append`mk)#[f]letys:=(←inst.collectFVars.run{}).2.fvarIds.mapExpr.fvarletinst←mkLambdaFVarsysinst>>=instantiateMVarsletf←mkLambdaFVarsysf>>=instantiateMVarsletns←getCurrNamespaceletstrName:=ifid.getId.getNumParts>1thenid.getId.getPrefixelsens-- Handle member function caseif(←getEnv).containsstrNamethen-- Resolve namespace properlyletF←inferTypefletfunName:=id.getId.getString!letstrId←resolveGlobalConstNoOverload(mkIdentstrName)letdeclId:=strId.append(.mkSimplefunName)lethints:=ReducibilityHints.regular(getMaxHeight(←getEnv)f+1)letdecl←Lean.mkDefinitionValInferringUnsafedeclId[]FfhintsaddDeclarationRangesFromSyntaxdeclIdid-- Add documentation if providedmatchdocwith|somedoc=>addDecl(Declaration.defnDecldecl)addDocStringdeclId(mkNullNodebs)doccompileDecl(Declaration.defnDecldecl)|none=>addAndCompile(Declaration.defnDecldecl)-- Generate and add instanceletclassExpr←inferTypeinstletinstName:=(←getCurrNamespace)++(←NameGen.mkBaseNameWithSuffix"inst"classExpr)if(←getEnv).containsinstNamethenthrowError"Enviroment already contains {instName}"lethints:=ReducibilityHints.regular(getMaxHeight(←getEnv)inst+1)letdecl←Lean.mkDefinitionValInferringUnsafeinstName[]classExprinsthintsaddAndCompile(Declaration.defnDecldecl)addInstanceinstNameAttributeKind.global(eval_priodefault)-- try to link `Foo.foo to the current `defun`letfunName:=className.append(.mkSimpleid.getId.getString!)addDeclarationRangesFromSyntaxfunNameiddeclfunfoo{α}(x:α):αdefunfoo(x:Nat):=10*xdefunfoo(x:Float):=10*x-- go to definition takes to `declfun foo {α} (x : α) : α`#checkfoo
Ohh nevermind, the whole question is completely moot.
#checkfoo(42:Nat)#checkfoo(42:Float)
using go-to-definition does take me to the right spot. There is some dark magic at play already! it seems like that it gives me an option to go to any of the instances that are applied to the current constant.
I will echo my support for this great feature!
Another useful feature is that Right click > Go to Declaration on notation will give you to the line where the notation was declared as an option to jump to.