diff --git a/gnovm/pkg/gnolang/preprocess.go b/gnovm/pkg/gnolang/preprocess.go index ee943226c85..a4576fa6f48 100644 --- a/gnovm/pkg/gnolang/preprocess.go +++ b/gnovm/pkg/gnolang/preprocess.go @@ -118,18 +118,6 @@ var preprocessing int // - Assigns BlockValuePath to NameExprs. // - TODO document what it does. func Preprocess(store Store, ctx BlockNode, n Node) Node { - // When panic, revert any package updates. - defer func() { - // Revert all new values. - // this is needed to revert top level - // function redeclarations. - if r := recover(); r != nil { - pkg := packageOf(ctx) - pkg.StaticBlock.revertToOld() - panic(r) - } - }() - // Increment preprocessing counter while preprocessing. { preprocessing += 1 @@ -2933,7 +2921,7 @@ func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (De } else { dt = rt.(*DeclaredType) } - dt.DefineMethod(&FuncValue{ + if !dt.TryDefineMethod(&FuncValue{ Type: ft, IsMethod: true, Source: cd, @@ -2943,7 +2931,13 @@ func predefineNow2(store Store, last BlockNode, d Decl, m map[Name]struct{}) (De PkgPath: pkg.PkgPath, body: cd.Body, nativeBody: nil, - }) + }) { + // Revert to old function declarations in the package we're preprocessing. + pkg := packageOf(last) + pkg.StaticBlock.revertToOld() + panic(fmt.Sprintf("redeclaration of method %s.%s", + dt.Name, cd.Name)) + } } else { ftv := pkg.GetValueRef(store, cd.Name) ft := ftv.T.(*FuncType) diff --git a/gnovm/pkg/gnolang/types.go b/gnovm/pkg/gnolang/types.go index 65bf7227458..34565b7a1b6 100644 --- a/gnovm/pkg/gnolang/types.go +++ b/gnovm/pkg/gnolang/types.go @@ -1451,43 +1451,53 @@ func (dt *DeclaredType) GetPkgPath() string { } func (dt *DeclaredType) DefineMethod(fv *FuncValue) { + if !dt.TryDefineMethod(fv) { + panic(fmt.Sprintf("redeclaration of method %s.%s", + dt.Name, fv.Name)) + } +} + +// TryDefineMethod attempts to define the method fv on type dt. +// It returns false if this does not succeeds, as a result of a re-declaration. +func (dt *DeclaredType) TryDefineMethod(fv *FuncValue) bool { name := fv.Name // Handle redeclarations. for i, tv := range dt.Methods { ofv := tv.V.(*FuncValue) - if ofv.Name == name { - // Do not allow redeclaring (override) a method. - // In the future we may allow this, just like we - // allow package-level function overrides. - - // Special case: if the type and location are the same, - // ignore and do not redefine. - // This is due to PreprocessAllFilesAndSaveBlocknodes, - // and because the preprocessor fills some of the - // method's FuncValue. Since the method was already - // filled in prior to PreprocessAllFilesAndSaveBlocks, - // there is no need to re-set it. - // Keep this or move this check outside. - if fv.Type.TypeID() == ofv.Type.TypeID() && - fv.Source.GetLocation() == ofv.Source.GetLocation() { - return - } + if ofv.Name != name { + continue + } - // Special case: allow defining a native body. - if fv.Type.TypeID() == ofv.Type.TypeID() && - !ofv.IsNative() && fv.IsNative() { - dt.Methods[i] = TypedValue{ - T: fv.Type, // keep old type. - V: fv, - } - return - } + // Do not allow redeclaring (override) a method. + // In the future we may allow this, just like we + // allow package-level function overrides. + + // Special case: if the type and location are the same, + // ignore and do not redefine. + // This is due to PreprocessAllFilesAndSaveBlocknodes, + // and because the preprocessor fills some of the + // method's FuncValue. Since the method was already + // filled in prior to PreprocessAllFilesAndSaveBlocks, + // there is no need to re-set it. + // Keep this or move this check outside. + if fv.Type.TypeID() == ofv.Type.TypeID() && + fv.Source.GetLocation() == ofv.Source.GetLocation() { + return true + } - // Otherwise panic. - panic(fmt.Sprintf("redeclaration of method %s.%s", - dt.Name, name)) + // Special case: allow defining a native body. + if fv.Type.TypeID() == ofv.Type.TypeID() && + !ofv.IsNative() && fv.IsNative() { + dt.Methods[i] = TypedValue{ + T: fv.Type, // keep old type. + V: fv, + } + return true } + + // Otherwise fail and return false. + return false } // If not redeclaring, just append. @@ -1495,6 +1505,7 @@ func (dt *DeclaredType) DefineMethod(fv *FuncValue) { T: fv.Type, V: fv, }) + return true } func (dt *DeclaredType) GetPathForName(n Name) ValuePath {