Skip to content

Commit

Permalink
Merge pull request #40255 from KavinduZoysa/do-clause-after-gby
Browse files Browse the repository at this point in the history
Support sequence variables inside do-clause
  • Loading branch information
gimantha committed Apr 24, 2023
2 parents a04c354 + 403fb04 commit 7e1fc7b
Show file tree
Hide file tree
Showing 8 changed files with 853 additions and 271 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -519,8 +519,7 @@ private void addClassMemberFunctionsToTopLevel(BLangPackage pkgNode, SymbolEnv e
BLangFunction tempGeneratedInitFunction = createGeneratedInitializerFunction(classDefinition, env);
tempGeneratedInitFunction.clonedEnv = SymbolEnv.createFunctionEnv(tempGeneratedInitFunction,
tempGeneratedInitFunction.symbol.scope, env);
SemanticAnalyzer.AnalyzerData data = new SemanticAnalyzer.AnalyzerData(env);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, data);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, env);
classDefinition.generatedInitFunction = tempGeneratedInitFunction;

// Add generated init function to the attached function list
Expand Down Expand Up @@ -8046,8 +8045,7 @@ private BLangClassDefinition desugarTemplateLiteralObjectTypedef(List<BLangLiter
BLangFunction tempGeneratedInitFunction = createGeneratedInitializerFunction(classDef, env);
tempGeneratedInitFunction.clonedEnv = SymbolEnv.createFunctionEnv(tempGeneratedInitFunction,
tempGeneratedInitFunction.symbol.scope, env);
SemanticAnalyzer.AnalyzerData data = new SemanticAnalyzer.AnalyzerData(env);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, data);
this.semanticAnalyzer.analyzeNode(tempGeneratedInitFunction, env);
classDef.generatedInitFunction = tempGeneratedInitFunction;
env.enclPkg.functions.add(classDef.generatedInitFunction);
env.enclPkg.topLevelNodes.add(classDef.generatedInitFunction);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@
import org.wso2.ballerinalang.compiler.tree.expressions.BLangQueryAction;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangQueryExpr;
import org.wso2.ballerinalang.compiler.tree.expressions.BLangSimpleVarRef;
import org.wso2.ballerinalang.compiler.tree.statements.BLangDo;
import org.wso2.ballerinalang.compiler.tree.types.BLangLetVariable;
import org.wso2.ballerinalang.compiler.tree.types.BLangType;
import org.wso2.ballerinalang.compiler.util.BArrayState;
Expand Down Expand Up @@ -240,7 +239,7 @@ public void checkQueryAction(BLangQueryAction queryAction, TypeChecker.AnalyzerD
BType completionType = getCompletionType(collectionTypes, Types.QueryConstructType.ACTION, data);
// Analyze foreach node's statements.
semanticAnalyzer.analyzeNode(doClause.body, SymbolEnv.createBlockEnv(doClause.body,
commonAnalyzerData.queryEnvs.peek()), data.prevEnvs, commonAnalyzerData);
commonAnalyzerData.queryEnvs.peek()), data.prevEnvs, this, commonAnalyzerData);
BType actualType = completionType == null ? symTable.nilType : completionType;
data.resultType = types.checkType(doClause.pos, actualType, data.expType,
DiagnosticErrorCode.INCOMPATIBLE_TYPES);
Expand Down Expand Up @@ -701,7 +700,7 @@ public void visit(BLangLetClause letClause, TypeChecker.AnalyzerData data) {
letClause.env = letEnv;
commonAnalyzerData.queryEnvs.push(letEnv);
for (BLangLetVariable letVariable : letClause.letVarDeclarations) {
semanticAnalyzer.analyzeNode((BLangNode) letVariable.definitionNode, letEnv, commonAnalyzerData);
semanticAnalyzer.analyzeNode((BLangNode) letVariable.definitionNode, letEnv, this, commonAnalyzerData);
}
for (Name variable : letEnv.scope.entries.keySet()) {
data.queryVariables.add(variable.value);
Expand Down Expand Up @@ -790,7 +789,7 @@ public void visit(BLangGroupByClause groupByClause, TypeChecker.AnalyzerData dat
checkExpr(groupingKey.variableRef, groupByClause.env, data);
variable = groupingKey.variableRef.variableName.value;
} else {
semanticAnalyzer.analyzeNode(groupingKey.variableDef, groupByClause.env,
semanticAnalyzer.analyzeNode(groupingKey.variableDef, groupByClause.env, this,
data.commonAnalyzerData);
variable = groupingKey.variableDef.var.name.value;
}
Expand All @@ -811,13 +810,6 @@ public void visit(BLangGroupingKey node, TypeChecker.AnalyzerData data) {

}

@Override
public void visit(BLangDo doNode, TypeChecker.AnalyzerData data) {
if (doNode.onFailClause != null) {
doNode.onFailClause.accept(this, data);
}
}

@Override
public void visit(BLangCheckedExpr checkedExpr, TypeChecker.AnalyzerData data) {
visitCheckAndCheckPanicExpr(checkedExpr, data);
Expand All @@ -828,9 +820,10 @@ public void visit(BLangCheckedExpr checkedExpr, TypeChecker.AnalyzerData data) {

public void visit(BLangInvocation iExpr, TypeChecker.AnalyzerData data) {
// Check whether the invocation happens after group by and arguments contain sequence variables
if (checkInvocationAfterGroupBy(iExpr, data)) {
if (hasSequenceArgs(iExpr, data)) {
// Do complete type checking for the invocation
Name pkgAlias = names.fromIdNode(iExpr.pkgAlias);
// TODO: Add more tests related to pkg alias
if (pkgAlias.value.isEmpty()) {
if (iExpr.expr != null) {
BType exprType = checkExpr(iExpr.expr, data);
Expand Down Expand Up @@ -917,19 +910,28 @@ public void visit(BLangInvocation iExpr, TypeChecker.AnalyzerData data) {
}

// Check the argument within sequence context.
private boolean hasSequenceArgs(BLangInvocation invocation, TypeChecker.AnalyzerData data) {
data.queryData.foundSeqVarInExpr = false;
for (BLangExpression arg : invocation.argExprs) {
if (arg.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
silentTypeCheckExpr(arg, symTable.noType, data);
}
}
return data.queryData.foundSeqVarInExpr;
}

private void checkArg(BLangExpression arg, BType expectedType, TypeChecker.AnalyzerData data) {
data.queryData.withinSequenceContext = effectiveSimpleVarRef(arg);
checkTypeParamExpr(arg, expectedType, data);
data.queryData.withinSequenceContext = false;
}

private boolean effectiveSimpleVarRef(BLangExpression expr) {
// TODO: Improve this method to handle grouping-expr
NodeKind kind = expr.getKind();
return kind == NodeKind.SIMPLE_VARIABLE_REF;
}

// TODO: Combine this with the method in TypeChecker
public void visit(BLangSimpleVarRef varRefExpr, TypeChecker.AnalyzerData data) {
// Set error type as the actual type.
BType actualType = symTable.semanticError;
Expand Down Expand Up @@ -1028,12 +1030,6 @@ public void visit(BLangSimpleVarRef varRefExpr, TypeChecker.AnalyzerData data) {
data.resultType = types.checkType(varRefExpr, actualType, data.expType);
}

private boolean checkInvocationAfterGroupBy(BLangInvocation invocation, TypeChecker.AnalyzerData data) {
data.queryData.foundSeqVarInExpr = false;
invocation.argExprs.forEach(arg -> silentTypeCheckExpr(arg, symTable.noType, data));
return data.queryData.foundSeqVarInExpr;
}

@Override
public void visit(BLangListConstructorExpr listConstructor, TypeChecker.AnalyzerData data) {
// TODO: Refactor this method
Expand All @@ -1053,6 +1049,12 @@ public void visit(BLangListConstructorExpr listConstructor, TypeChecker.Analyzer
if (expr.getKind() == NodeKind.SIMPLE_VARIABLE_REF) {
BType type = silentTypeCheckExpr(expr, symTable.noType, data);
if (type.tag == TypeTags.SEQUENCE) {
// TODO: There is another type of doing this
// First check the expr with expType = noType
// Use the result type to generate the type of list-ctr
// Then check the expType is an array or tuple
// Then do the type check for element types
// This may cause to remove the type checking part for seq from Types.java
data.queryData.withinSequenceContext = true;
checkExpr(expr, data.env, expType, data);
data.queryData.withinSequenceContext = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ public class SemanticAnalyzer extends SimpleBLangNodeAnalyzer<SemanticAnalyzer.A
private final Types types;
private final Unifier unifier;
private final Stack<String> anonTypeNameSuffixes;
private final CompilerContext compilerContext;

public static SemanticAnalyzer getInstance(CompilerContext context) {
SemanticAnalyzer semAnalyzer = context.get(SYMBOL_ANALYZER_KEY);
Expand All @@ -281,6 +282,7 @@ public static SemanticAnalyzer getInstance(CompilerContext context) {

private SemanticAnalyzer(CompilerContext context) {
context.put(SYMBOL_ANALYZER_KEY, this);
compilerContext = context;

this.symTable = SymbolTable.getInstance(context);
this.symbolEnter = SymbolEnter.getInstance(context);
Expand Down Expand Up @@ -612,7 +614,7 @@ private boolean analyzeBlockStmtFollowingIfWithoutElse(BLangStatement currentStm
@Override
public void visit(BLangExprFunctionBody body, AnalyzerData data) {
SymbolEnv env = SymbolEnv.createFuncBodyEnv(body, data.env);
typeChecker.checkExpr(body.expr, env, data.expType, data.prevEnvs, data.commonAnalyzerData);
data.typeChecker.checkExpr(body.expr, env, data.expType, data.prevEnvs, data.commonAnalyzerData);
}

@Override
Expand Down Expand Up @@ -1205,13 +1207,7 @@ public void visit(BLangSimpleVariable varNode, AnalyzerData data) {
data.commonAnalyzerData);
validateListenerCompatibility(varNode, rhsType);
} else {
// let int _ = check getDistinctErrorOrInt()
if (data.commonAnalyzerData.queryEnvs.empty()) {
typeChecker.checkExpr(rhsExpr, varInitEnv, lhsType, data.prevEnvs, data.commonAnalyzerData);
} else {
typeChecker.queryTypeChecker.checkExpr(rhsExpr, varInitEnv, lhsType, data.prevEnvs,
data.commonAnalyzerData);
}
data.typeChecker.checkExpr(rhsExpr, varInitEnv, lhsType, data.prevEnvs, data.commonAnalyzerData);
}

checkSelfReferencesInVarNode(varNode, rhsExpr, data);
Expand Down Expand Up @@ -2260,7 +2256,7 @@ public void visit(BLangCompoundAssignment compoundAssignment, AnalyzerData data)
expType = symTable.semanticError;
}

this.typeChecker.checkExpr(compoundAssignment.expr, currentEnv, data.prevEnvs, data.commonAnalyzerData);
data.typeChecker.checkExpr(compoundAssignment.expr, currentEnv, data.prevEnvs, data.commonAnalyzerData);

checkConstantAssignment(varRef, data);

Expand Down Expand Up @@ -2342,7 +2338,7 @@ public void visit(BLangAssignment assignNode, AnalyzerData data) {
}
}

typeChecker.checkExpr(assignNode.expr, data.env, data.expType, data.prevEnvs, data.commonAnalyzerData);
data.typeChecker.checkExpr(assignNode.expr, data.env, data.expType, data.prevEnvs, data.commonAnalyzerData);

validateWorkerAnnAttachments(assignNode.expr, data);

Expand Down Expand Up @@ -2808,7 +2804,7 @@ public void visit(BLangExpressionStmt exprStmtNode, AnalyzerData data) {
SymbolEnv stmtEnv = new SymbolEnv(exprStmtNode, currentEnv.scope);
currentEnv.copyTo(stmtEnv);
BLangExpression expr = exprStmtNode.expr;
BType bType = typeChecker.checkExpr(expr, stmtEnv, data.prevEnvs, data.commonAnalyzerData);
BType bType = data.typeChecker.checkExpr(expr, stmtEnv, data.prevEnvs, data.commonAnalyzerData);
if (!types.isAssignable(bType, symTable.nilType) && bType != symTable.semanticError &&
expr.getKind() != NodeKind.FAIL && !types.isNeverTypeOrStructureTypeWithARequiredNeverMember(bType)) {
dlog.error(exprStmtNode.pos, DiagnosticErrorCode.ASSIGNMENT_REQUIRED, bType);
Expand All @@ -2822,7 +2818,7 @@ public void visit(BLangExpressionStmt exprStmtNode, AnalyzerData data) {
@Override
public void visit(BLangIf ifNode, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
typeChecker.checkExpr(ifNode.expr, currentEnv, symTable.booleanType, data.prevEnvs,
data.typeChecker.checkExpr(ifNode.expr, currentEnv, symTable.booleanType, data.prevEnvs,
data.commonAnalyzerData);
BType actualType = ifNode.expr.getBType();
if (TypeTags.TUPLE == Types.getReferredType(actualType).tag) {
Expand Down Expand Up @@ -3847,7 +3843,7 @@ public void visit(BLangWildCardMatchPattern wildCardMatchPattern, AnalyzerData d
public void visit(BLangForeach foreach, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
// Check the collection's type.
typeChecker.checkExpr(foreach.collection, currentEnv, symTable.noType, data.prevEnvs,
data.typeChecker.checkExpr(foreach.collection, currentEnv, symTable.noType, data.prevEnvs,
data.commonAnalyzerData);
// object type collection should be a subtype of 'object:Iterable
if (Types.getReferredType(foreach.collection.getBType()).tag == TypeTags.OBJECT
Expand Down Expand Up @@ -3908,7 +3904,7 @@ public void visit(BLangGroupingKey node, AnalyzerData data) {
@Override
public void visit(BLangWhile whileNode, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
typeChecker.checkExpr(whileNode.expr, currentEnv, symTable.booleanType, data.prevEnvs,
data.typeChecker.checkExpr(whileNode.expr, currentEnv, symTable.booleanType, data.prevEnvs,
data.commonAnalyzerData);

if (whileNode.onFailClause != null) {
Expand Down Expand Up @@ -4248,8 +4244,8 @@ public void visit(BLangWorkerSend workerSendNode, AnalyzerData data) {
@Override
public void visit(BLangReturn returnNode, AnalyzerData data) {
SymbolEnv currentEnv = data.env;
this.typeChecker.checkExpr(returnNode.expr, currentEnv, currentEnv.enclInvokable.returnTypeNode.getBType(),
data.prevEnvs, data.commonAnalyzerData);
data.typeChecker.checkExpr(returnNode.expr, currentEnv, currentEnv.enclInvokable.returnTypeNode.getBType(),
data.prevEnvs, data.commonAnalyzerData);
validateWorkerAnnAttachments(returnNode.expr, data);
data.notCompletedNormally = true;
}
Expand All @@ -4263,12 +4259,26 @@ public void analyzeNode(BLangNode node, SymbolEnv env) {
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, QueryTypeChecker queryTypeChecker, SymbolEnv env) {
AnalyzerData data = new AnalyzerData(env);
data.typeChecker = queryTypeChecker;
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, SymbolEnv env, Types.CommonAnalyzerData commonAnalyzerData) {
AnalyzerData data = new AnalyzerData(env);
data.commonAnalyzerData = commonAnalyzerData;
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, SymbolEnv env, QueryTypeChecker queryTypeChecker,
Types.CommonAnalyzerData commonAnalyzerData) {
AnalyzerData data = new AnalyzerData(env);
data.commonAnalyzerData = commonAnalyzerData;
data.typeChecker = queryTypeChecker;
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, SymbolEnv env, Stack<SymbolEnv> prevEnvs) {
AnalyzerData data = new AnalyzerData(env);
data.prevEnvs = prevEnvs;
Expand All @@ -4282,6 +4292,16 @@ public void analyzeNode(BLangNode node, SymbolEnv env, Stack<SymbolEnv> prevEnvs
data.commonAnalyzerData = commonAnalyzerData;
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, SymbolEnv env, Stack<SymbolEnv> prevEnvs,
QueryTypeChecker queryTypeChecker, Types.CommonAnalyzerData commonAnalyzerData) {
AnalyzerData data = new AnalyzerData(env);
data.prevEnvs = prevEnvs;
data.commonAnalyzerData = commonAnalyzerData;
data.typeChecker = queryTypeChecker;
analyzeNode(node, data);
}

public void analyzeNode(BLangNode node, AnalyzerData data) {
analyzeNode(node, symTable.noType, data);
}
Expand Down Expand Up @@ -5050,15 +5070,17 @@ private Map<String, Location> getFieldLocations(List<BLangSimpleVariable> fields
/**
* @since 2.0.0
*/
public static class AnalyzerData {
public class AnalyzerData {
SymbolEnv env;
BType expType;
Map<BVarSymbol, BType.NarrowedTypes> narrowedTypeInfo;
boolean notCompletedNormally;
boolean breakFound;
Types.CommonAnalyzerData commonAnalyzerData = new Types.CommonAnalyzerData();
Stack<SymbolEnv> prevEnvs = new Stack<>();

// The `typeChecker` field is used to set the correct typeChecker to call in query context.
// TODO: Create new SemanticAnalyzer by extending current SemanticAnalyzer and use from QueryTypeChecker.
TypeChecker typeChecker = TypeChecker.getInstance(compilerContext);
public AnalyzerData(SymbolEnv env) {
this.env = env;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,18 @@ private boolean isAssignable(BType source, BType target, Set<TypePair> unresolve
return true;
}

if (sourceTag == TypeTags.SEQUENCE && targetTag == TypeTags.ARRAY) {
return isAssignable(((BSequenceType) source).elementType, ((BArrayType) target).eType,
unresolvedTypes);
if (sourceTag == TypeTags.SEQUENCE) {
BSequenceType seqType = (BSequenceType) source;
if (targetTag == TypeTags.ARRAY) {
return isAssignable(seqType.elementType, ((BArrayType) target).eType, unresolvedTypes);
}
if (targetTag == TypeTags.TUPLE) {
BTupleType tupleType = (BTupleType) target;
if (tupleType.restType == null) {
return false;
}
return isAssignable(seqType.elementType, ((BTupleType) target).restType, unresolvedTypes);
}
}

if (!Symbols.isFlagOn(source.flags, Flags.PARAMETERIZED) &&
Expand Down
Loading

0 comments on commit 7e1fc7b

Please sign in to comment.