Skip to content

Commit

Permalink
Merge pull request #18404 from MaryamZi/obj-reference-fixes
Browse files Browse the repository at this point in the history
Fix several issues with object type reference
  • Loading branch information
hasithaa authored Sep 2, 2019
2 parents 71c21cc + ccf5e3d commit 21f9a53
Show file tree
Hide file tree
Showing 35 changed files with 257 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public enum DiagnosticCode {
ABSTRACT_OBJECT_FUNCTION_CANNOT_HAVE_BODY("abstract.object.function.cannot.have.body"),
PRIVATE_OBJECT_CONSTRUCTOR("private.object.constructor"),
PRIVATE_FIELD_ABSTRACT_OBJECT("private.field.abstract.object"),
FIELD_WITH_DEFAULT_VALUE_ABSTRACT_OBJECT("field.with.default.value.abstract.object"),
PRIVATE_FUNC_ABSTRACT_OBJECT("private.function.abstract.object"),
EXTERN_FUNC_ABSTRACT_OBJECT("extern.function.abstract.object"),
RESOURCE_FUNCTION_CANNOT_BE_EXTERN("resource.function.cannot.be.extern"),
Expand Down Expand Up @@ -104,6 +105,7 @@ public enum DiagnosticCode {
EXPLICIT_WORKER_CANNOT_BE_DEFAULT("explicit.worker.cannot.be.default"),
INVALID_MULTIPLE_FORK_JOIN_SEND("worker.multiple.fork.join.send"),
INCOMPATIBLE_TYPE_REFERENCE("incompatible.type.reference"),
INCOMPATIBLE_TYPE_REFERENCE_NON_PUBLIC_MEMBERS("incompatible.type.reference.non.public.members"),
INCOMPATIBLE_RECORD_TYPE_REFERENCE("incompatible.record.type.reference"),
REDECLARED_TYPE_REFERENCE("redeclared.type.reference"),
REDECLARED_FUNCTION_FROM_TYPE_REFERENCE("redeclared.function.from.type.reference"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,14 @@ public void visit(BLangObjectTypeNode objectTypeNode) {
boolean isAbstract = objectTypeNode.flagSet.contains(Flag.ABSTRACT);
objectTypeNode.fields.forEach(field -> {
analyzeDef(field, objectEnv);
if (isAbstract && field.flagSet.contains(Flag.PRIVATE)) {
this.dlog.error(field.pos, DiagnosticCode.PRIVATE_FIELD_ABSTRACT_OBJECT, field.symbol.name);
if (isAbstract) {
if (field.flagSet.contains(Flag.PRIVATE)) {
this.dlog.error(field.pos, DiagnosticCode.PRIVATE_FIELD_ABSTRACT_OBJECT, field.symbol.name);
}

if (field.expr != null) {
this.dlog.error(field.expr.pos, DiagnosticCode.FIELD_WITH_DEFAULT_VALUE_ABSTRACT_OBJECT);
}
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.wso2.ballerinalang.compiler.semantics.model.types.BField;
import org.wso2.ballerinalang.compiler.semantics.model.types.BFutureType;
import org.wso2.ballerinalang.compiler.semantics.model.types.BInvokableType;
import org.wso2.ballerinalang.compiler.semantics.model.types.BObjectType;
import org.wso2.ballerinalang.compiler.semantics.model.types.BRecordType;
import org.wso2.ballerinalang.compiler.semantics.model.types.BServiceType;
import org.wso2.ballerinalang.compiler.semantics.model.types.BStructureType;
Expand Down Expand Up @@ -1284,6 +1285,7 @@ private void defineMembers(List<BLangTypeDefinition> typeDefNodes, SymbolEnv pkg
defineNode(f, objMethodsEnv);
});

List<String> referencedFunctions = new ArrayList<>();
// Add the attached functions of the referenced types to this object.
// Here it is assumed that all the attached functions of the referred type are
// resolved by the time we reach here. It is achieved by ordering the typeDefs
Expand All @@ -1295,7 +1297,7 @@ private void defineMembers(List<BLangTypeDefinition> typeDefNodes, SymbolEnv pkg

List<BAttachedFunction> functions = ((BObjectTypeSymbol) typeRef.type.tsymbol).attachedFuncs;
for (BAttachedFunction function : functions) {
defineReferencedFunction(typeDef, objMethodsEnv, typeRef, function);
defineReferencedFunction(typeDef, objMethodsEnv, typeRef, function, referencedFunctions);
}
}
} else if (typeDef.symbol.kind == SymbolKind.RECORD) {
Expand Down Expand Up @@ -1688,6 +1690,7 @@ private void createDummyTypeDefSymbol(TypeDefinition typeDefNode, SymbolEnv env)

private void resolveReferencedFields(BLangStructureTypeNode structureTypeNode, SymbolEnv typeDefEnv) {
List<BSymbol> referencedTypes = new ArrayList<>();
List<BLangType> invalidTypeRefs = new ArrayList<>();
// Get the inherited fields from the type references
structureTypeNode.referencedFields = structureTypeNode.typeRefs.stream().flatMap(typeRef -> {
BType referredType = symResolver.resolveTypeNode(typeRef, typeDefEnv);
Expand All @@ -1698,13 +1701,28 @@ private void resolveReferencedFields(BLangStructureTypeNode structureTypeNode, S
// Check for duplicate type references
if (referencedTypes.contains(referredType.tsymbol)) {
dlog.error(typeRef.pos, DiagnosticCode.REDECLARED_TYPE_REFERENCE, typeRef);
invalidTypeRefs.add(typeRef);
return Stream.empty();
}

if (structureTypeNode.type.tag == TypeTags.OBJECT && (referredType.tag != TypeTags.OBJECT || !Symbols
.isFlagOn(referredType.tsymbol.flags, Flags.ABSTRACT))) {
dlog.error(typeRef.pos, DiagnosticCode.INCOMPATIBLE_TYPE_REFERENCE, typeRef);
return Stream.empty();
if (structureTypeNode.type.tag == TypeTags.OBJECT) {
if (referredType.tag != TypeTags.OBJECT ||
!Symbols.isFlagOn(referredType.tsymbol.flags, Flags.ABSTRACT)) {
dlog.error(typeRef.pos, DiagnosticCode.INCOMPATIBLE_TYPE_REFERENCE, typeRef);
invalidTypeRefs.add(typeRef);
return Stream.empty();
}

BObjectType objectType = (BObjectType) referredType;
if (structureTypeNode.type.tsymbol.owner != referredType.tsymbol.owner) {
if (objectType.fields.stream().anyMatch(field -> !Symbols.isPublic(field.symbol)) ||
((BObjectTypeSymbol) objectType.tsymbol).attachedFuncs.stream()
.anyMatch(func -> !Symbols.isPublic(func.symbol))) {
dlog.error(typeRef.pos, DiagnosticCode.INCOMPATIBLE_TYPE_REFERENCE_NON_PUBLIC_MEMBERS, typeRef);
invalidTypeRefs.add(typeRef);
return Stream.empty();
}
}
}

if (structureTypeNode.type.tag == TypeTags.RECORD && referredType.tag != TypeTags.RECORD) {
Expand All @@ -1724,15 +1742,23 @@ private void resolveReferencedFields(BLangStructureTypeNode structureTypeNode, S
return var;
});
}).collect(Collectors.toList());
structureTypeNode.typeRefs.removeAll(invalidTypeRefs);
}

private void defineReferencedFunction(BLangTypeDefinition typeDef, SymbolEnv objEnv, BLangType typeRef,
BAttachedFunction referencedFunc) {
BAttachedFunction referencedFunc, List<String> referencedFunctions) {
String referencedFuncName = referencedFunc.funcName.value;
Name funcName = names.fromString(
Symbols.getAttachedFuncSymbolName(typeDef.symbol.name.value, referencedFunc.funcName.value));
Symbols.getAttachedFuncSymbolName(typeDef.symbol.name.value, referencedFuncName));
BSymbol matchingObjFuncSym = symResolver.lookupSymbol(objEnv, funcName, SymTag.VARIABLE);

if (matchingObjFuncSym != symTable.notFoundSymbol) {
if (referencedFunctions.contains(referencedFuncName)) {
dlog.error(typeRef.pos, DiagnosticCode.REDECLARED_SYMBOL, referencedFuncName);
return;
}
referencedFunctions.add(referencedFuncName);

if (Symbols.isFunctionDeclaration(matchingObjFuncSym) && Symbols.isFunctionDeclaration(
referencedFunc.symbol)) {
Optional<BLangFunction> matchingFunc = ((BLangObjectTypeNode) typeDef.typeNode)
Expand Down Expand Up @@ -1791,7 +1817,10 @@ private boolean hasSameFunctionSignature(BInvokableSymbol attachedFuncSym, BInvo

List<BVarSymbol> params = referencedFuncSym.params;
for (int i = 0; i < params.size(); i++) {
if (!params.get(i).name.value.equals(attachedFuncSym.params.get(i).name.value)) {
BVarSymbol referencedFuncParam = params.get(i);
BVarSymbol attachedFuncParam = attachedFuncSym.params.get(i);
if (!referencedFuncParam.name.value.equals(attachedFuncParam.name.value) ||
!hasSameVisibilityModifier(referencedFuncParam.flags, attachedFuncParam.flags)) {
return false;
}
}
Expand Down Expand Up @@ -1822,7 +1851,8 @@ private String getCompleteFunctionSignature(BInvokableSymbol funcSymbol) {
signatureBuilder.append(visibilityModifier).append("function ")
.append(funcSymbol.name.value.split("\\.")[1]);

funcSymbol.params.forEach(param -> paramListBuilder.add(param.type.toString() + " " + param.name.value));
funcSymbol.params.forEach(param -> paramListBuilder.add(
(Symbols.isPublic(param) ? "public " : "") + param.type.toString() + " " + param.name.value));

if (funcSymbol.restParam != null) {
paramListBuilder.add(((BArrayType) funcSymbol.restParam.type).eType.toString() + "... " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,9 @@ error.private.object.constructor=\
error.private.field.abstract.object=\
abstract object field: ''{0}'' can not be declared as private

error.field.with.default.value.abstract.object=\
fields with default values are not yet supported with abstract objects

error.private.function.abstract.object=\
interface function: ''{0}'' of abstract object ''{1}'' can not be declared as private

Expand All @@ -742,6 +745,9 @@ error.extern.function.abstract.object=\
error.incompatible.type.reference=\
incompatible types: ''{0}'' is not an abstract object

error.incompatible.type.reference.non.public.members=\
incompatible type reference ''{0}'': a referenced object cannot have non-public fields or methods

error.incompatible.record.type.reference=\
incompatible types: ''{0}'' is not a record

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public type DelayWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ public type ExternalTimeBatchWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public type ExternalTimeWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public type HoppingWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public type LengthBatchWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public type LengthWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public type SortWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ public type TimeAccumulatingWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public type TimeBatchWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public type TimeLengthWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public type TimeOrderWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public type TimeWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ public type UniqueLengthWindow object {
public function getCandidateEvents(
StreamEvent originEvent,
(function (map<anydata> e1Data, map<anydata> e2Data) returns boolean)? conditionFunc,
boolean isLHSTrigger = true)
public boolean isLHSTrigger = true)
returns @tainted [StreamEvent?, StreamEvent?][] {
[StreamEvent?, StreamEvent?][] events = [];
int i = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public type UProtocol LocalProtocol|RemoteProtocol;

type Participant abstract object {

string participantId = "";
string participantId;

function prepare(string protocol) returns [(PrepareResult|error)?, Participant];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void setup() {
public void testAbstractObjectNegative() {
CompileResult negativeResult = BCompileUtil.compile("test-src/object/abstract-object-negative.bal");
int index = 0;
Assert.assertEquals(negativeResult.getErrorCount(), 11);
Assert.assertEquals(negativeResult.getErrorCount(), 12);
BAssertUtil.validateError(negativeResult, index++, "cannot initialize abstract object 'Person1'", 3, 18);
BAssertUtil.validateError(negativeResult, index++, "cannot initialize abstract object 'Person2'", 4, 18);
BAssertUtil.validateError(negativeResult, index++, "cannot initialize abstract object 'Person1'", 8, 18);
Expand All @@ -61,8 +61,10 @@ public void testAbstractObjectNegative() {
"'Person6' can not be declared as private", 61, 5);
BAssertUtil.validateError(negativeResult, index++, "interface function: 'getName' of abstract object 'Foo' " +
"can not be declared as private", 65, 5);
BAssertUtil.validateError(negativeResult, index,
BAssertUtil.validateError(negativeResult, index++,
"external function: 'getName' not allowed in abstract object 'Person7'", 78, 5);
BAssertUtil.validateError(negativeResult, index,
"fields with default values are not yet supported with abstract objects", 83, 18);
}

@Test
Expand Down
Loading

0 comments on commit 21f9a53

Please sign in to comment.