Repository: openllb/hlb
Pull request #202 (2020-11-11 19:11:22)

Fix remote modules importing local paths and improve no bind closure error
### Improved no bind closure error
![bind-closure](https://user-images.githubusercontent.com/6493975/98853830-9271b680-240e-11eb-981f-da67fa313888.png)

## Fixed remote modules importing local paths
![bt-remote-local](https://user-images.githubusercontent.com/6493975/98853855-9b628800-240e-11eb-813f-4e93874e8950.png)


Patch:
diff --git a/checker/checker.go b/checker/checker.go
index 471b5a2..8eabb90 100644
--- a/checker/checker.go
+++ b/checker/checker.go
@@ -100,7 +100,7 @@ func (c *checker) SemanticPass(mod *parser.Module) error {
 			// Propagate scope and type into its BlockStmt.
 			if fun.Body != nil {
 				fun.Body.Scope = fun.Scope
-				fun.Body.Kind = fun.Type.Kind
+				fun.Body.Type = fun.Type
 
 				// BindClause rule (1): Option blocks do not have a closure for bindings.
 				if fun.Type.Kind.Primary() != parser.Option {
@@ -111,7 +111,7 @@ func (c *checker) SemanticPass(mod *parser.Module) error {
 		// Function literals propagate its return type to its BlockStmt.
 		func(lit *parser.FuncLit) {
 			if lit.Type.Kind != parser.Option {
-				lit.Body.Kind = lit.Type.Kind
+				lit.Body.Type = lit.Type
 			}
 		},
 		// ImportDecl's BlockStmts have module-level scope.
@@ -131,10 +131,9 @@ func (c *checker) SemanticPass(mod *parser.Module) error {
 		// `option` type function literal, but infers its type as `option::run`.
 		func(call *parser.CallStmt, with *parser.WithClause, lit *parser.FuncLit) {
 			if lit.Type.Kind == parser.Option {
-				lit.Body.Kind = parser.Kind(fmt.Sprintf("%s::%s", parser.Option, call.Name.Ident))
-			} else {
-				lit.Body.Kind = lit.Type.Kind
+				lit.Type.Kind = parser.Kind(fmt.Sprintf("%s::%s", lit.Type.Kind, call.Name.Ident))
 			}
+			lit.Body.Type = lit.Type
 		},
 	)
 
@@ -179,15 +178,15 @@ func (c *checker) checkBinds(mod *parser.Module) {
 			}
 
 			// Pass the block's closure for the binding.
-			err := c.registerBinds(mod.Scope, block.Kind, block.Closure, call, binds)
+			err := c.registerBinds(mod.Scope, block.Kind(), block.Closure, call, binds)
 			if err != nil {
 				c.err(err)
 			}
 		},
 		// Binds without closure should error.
-		func(binds *parser.BindClause) {
+		func(block *parser.BlockStmt, binds *parser.BindClause) {
 			if binds.Closure == nil {
-				c.err(errdefs.WithNoBindClosure(binds.As))
+				c.err(errdefs.WithNoBindClosure(binds.As, block.Type))
 			}
 		},
 	)
@@ -295,7 +294,7 @@ func (c *checker) checkFieldList(fields []*parser.Field) error {
 
 func (c *checker) checkBlock(block *parser.BlockStmt) error {
 	for _, stmt := range block.Stmts() {
-		kset := parser.NewKindSet(block.Kind)
+		kset := parser.NewKindSet(block.Kind())
 
 		var err error
 		switch {
diff --git a/codegen/codegen.go b/codegen/codegen.go
index ae05a34..94457ae 100644
--- a/codegen/codegen.go
+++ b/codegen/codegen.go
@@ -404,7 +404,7 @@ func (cg *CodeGen) EmitBinding(ctx context.Context, b *parser.Binding, args []Va
 }
 
 func (cg *CodeGen) EmitBlock(ctx context.Context, scope *parser.Scope, block *parser.BlockStmt, b *parser.Binding, ret Register) error {
-	ctx = WithReturnType(ctx, block.Kind)
+	ctx = WithReturnType(ctx, block.Kind())
 
 	for _, stmt := range block.Stmts() {
 		var err error
diff --git a/errdefs/errors.go b/errdefs/errors.go
index 19feb8a..664de7f 100644
--- a/errdefs/errors.go
+++ b/errdefs/errors.go
@@ -159,10 +159,11 @@ func WithNoBindTarget(as parser.Node) error {
 	)
 }
 
-func WithNoBindClosure(as parser.Node) error {
+func WithNoBindClosure(as, option parser.Node) error {
 	return as.WithError(
-		fmt.Errorf("cannot bind, no function register in scope"),
-		as.Spanf(diagnostic.Primary, "no function register in scope"),
+		fmt.Errorf("cannot bind, no closure in option blocks"),
+		as.Spanf(diagnostic.Primary, "no closure for binding"),
+		option.Spanf(diagnostic.Secondary, "option blocks have no closures outside of \"with option {...}\""),
 	)
 }
 
diff --git a/langserver/server.go b/langserver/server.go
index 61bf987..b681edc 100644
--- a/langserver/server.go
+++ b/langserver/server.go
@@ -662,7 +662,7 @@ func (ls *LangServer) textDocumentHoverHandler(ctx context.Context, params lsp.T
 			},
 		},
 		func(block *parser.BlockStmt, ident *parser.Ident) {
-			lookupByKind, ok := builtin.Lookup.ByKind[block.Kind]
+			lookupByKind, ok := builtin.Lookup.ByKind[block.Kind()]
 			if !ok {
 				return
 			}
diff --git a/module/resolve.go b/module/resolve.go
index d8dfc69..77bf63f 100644
--- a/module/resolve.go
+++ b/module/resolve.go
@@ -399,10 +399,7 @@ func resolveGraph(ctx context.Context, info *resolveGraphInfo, res Resolved, mod
 					return err
 				}
 
-				var (
-					ires     Resolved
-					filename string
-				)
+				var filename string
 				switch ret.Kind() {
 				case parser.Filesystem:
 					fs, err := ret.Filesystem()
@@ -411,25 +408,27 @@ func resolveGraph(ctx context.Context, info *resolveGraphInfo, res Resolved, mod
 					}
 
 					filename = ModuleFilename
-					ires, err = info.resolver.Resolve(ctx, id, fs)
+					res, err = info.resolver.Resolve(ctx, id, fs)
 					if err != nil {
 						return err
 					}
-					defer ires.Close()
+					defer res.Close()
+
 				case parser.String:
-					ires = res
-					relPath, err := ret.String()
+					filename, err = ret.String()
 					if err != nil {
 						return err
 					}
 
-					filename, err = parser.ResolvePath(codegen.ModuleDir(ctx), relPath)
-					if err != nil {
-						return err
+					if _, ok := res.(*localResolved); ok {
+						filename, err = parser.ResolvePath(codegen.ModuleDir(ctx), filename)
+						if err != nil {
+							return err
+						}
 					}
 				}
 
-				rc, err := ires.Open(filename)
+				rc, err := res.Open(filename)
 				if err != nil {
 					if !os.IsNotExist(err) {
 						return err
@@ -470,14 +469,14 @@ func resolveGraph(ctx context.Context, info *resolveGraphInfo, res Resolved, mod
 						Import:     imod,
 						ImportDecl: id,
 						Ret:        ret,
-						Digest:     ires.Digest(),
+						Digest:     res.Digest(),
 					})
 					if err != nil {
 						return err
 					}
 				}
 
-				return resolveGraph(ctx, info, ires, imod)
+				return resolveGraph(ctx, info, res, imod)
 			})
 		},
 	)
diff --git a/parser/cst.go b/parser/cst.go
index 40b4b32..1f1d952 100644
--- a/parser/cst.go
+++ b/parser/cst.go
@@ -398,7 +398,7 @@ type Variadic struct {
 type BlockStmt struct {
 	Mixin
 	Scope     *Scope
-	Kind      Kind
+	Type      *Type
 	Closure   *FuncDecl
 	Start     *OpenBrace  `parser:"@@"`
 	List      []*Stmt     `parser:"@@*"`
@@ -409,6 +409,13 @@ func NewBlockStmt(stmts ...*Stmt) *BlockStmt {
 	return &BlockStmt{List: stmts}
 }
 
+func (bs *BlockStmt) Kind() Kind {
+	if bs.Type == nil {
+		return None
+	}
+	return bs.Type.Kind
+}
+
 func (bs *BlockStmt) Stmts() []*Stmt {
 	if bs == nil {
 		return nil


Test patch:
diff --git a/checker/checker_test.go b/checker/checker_test.go
index d7f53f8..da52b7e 100644
--- a/checker/checker_test.go
+++ b/checker/checker_test.go
@@ -442,6 +442,7 @@ func TestChecker_Check(t *testing.T) {
 		func(mod *parser.Module) error {
 			return errdefs.WithNoBindClosure(
 				parser.Find(mod, "as"),
+				parser.Find(mod, "option::run"),
 			)
 		},
 	}, {
@@ -460,6 +461,7 @@ func TestChecker_Check(t *testing.T) {
 		func(mod *parser.Module) error {
 			return errdefs.WithNoBindClosure(
 				parser.Find(mod, "as"),
+				parser.Find(mod, "option::run"),
 			)
 		},
 	}} {