Skip to content

Commit

Permalink
Merge pull request #1889 from uqbar-project/polymorphic-method-type
Browse files Browse the repository at this point in the history
Polymorphic method type
  • Loading branch information
PalumboN authored Jun 8, 2020
2 parents 8dc8bc4 + 3170e08 commit f7f3f84
Show file tree
Hide file tree
Showing 20 changed files with 441 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,21 @@ abstract class AbstractWollokTypeSystemTestCase extends AbstractWollokParameteri
}

def assertIssuesInElement(EObject element, String... expectedIssues) {
val expectedDiagnostics = expectedIssues.map [ message |
diagnose.assertAll(element.expectedDiagnosticsexpectedDiagnostics(expectedIssues))
}

def assertAnyIssueInElement(EObject element, String... expectedIssues) {
diagnose.assertAny(element.expectedDiagnosticsexpectedDiagnostics(expectedIssues))
}

def expectedDiagnosticsexpectedDiagnostics(EObject element, String... expectedIssues) {
expectedIssues.map [ message |
new AssertableDiagnostics.Pred(null, null, null, message) {
override apply(Diagnostic d) {
super.apply(d) && (d as AbstractValidationDiagnostic).sourceEObject == element
}
}
]
diagnose.assertAll(expectedDiagnostics)
}

// FINDS
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package org.uqbar.project.wollok.tests.typesystem

import org.eclipse.emf.ecore.EObject
import org.junit.Test
import org.junit.runners.Parameterized.Parameters
import org.uqbar.project.wollok.typesystem.constraints.ConstraintBasedTypeSystem
import org.uqbar.project.wollok.wollokDsl.WMemberFeatureCall

class CompatibleTypeInferenceTestCase extends AbstractWollokTypeSystemTestCase {

@Parameters(name="{index}: {0}")
static def Object[] typeSystems() {
#[
ConstraintBasedTypeSystem
]
}

@Test
def void variableWithBasicTypes() {
'''
program {
var x = ""
x = 0
}
'''.parseAndInfer.asserting [
findByText("x").assertIncompatibleTypesIssue("String", "Number")
assertTypeOfAsString("(Number|String)", "x")
]
}

@Test
def void variableWithWKOs() {
'''
object obj1 { }
object obj2 { }
program {
var x = obj1
x = obj2
}
'''.parseAndInfer.asserting [
noIssues
assertTypeOfAsString("(obj1|obj2)", "x")
]
}

@Test
def void variableWithBasicTypeAndWKO() {
'''
object obj { }
program {
var x = 0
x = obj
}
'''.parseAndInfer.asserting [
noIssues
assertTypeOfAsString("(Number|obj)", "x")
]
}

@Test
def void propertyWithBasicTypes() {
'''
object testing {
method test1() {
obj.n("")
}
}
object obj {
var property n = 0
}
'''.parseAndInfer.asserting [
findByText('''""''').assertIncompatibleTypesIssue("String", "Number")
]
}

@Test
def void propertyWithWKOs() {
'''
object obj1 { }
object obj2 { }
object testing {
method test1() {
obj.x(obj2)
}
}
object obj {
var property x = obj1
}
'''.parseAndInfer.asserting [
// FIXME
// noIssues
findByText('''obj2''').assertIncompatibleTypesIssue("obj1", "obj2")
]
}

@Test
def void parameterType() {
'''
object testing {
method test1() {
obj.boolean("")
}
}
object obj {
method boolean(bool) { return if (bool) 2 else 3 }
}
'''.parseAndInfer.asserting [
findByText('''""''').assertIncompatibleTypesIssue("String", "Boolean")
assertMethodSignature("(Boolean) => Number", "obj.boolean")
]
}

@Test
def void returnType() {
'''
object obj {
var bool
method boolean() { return if (bool) 2 else "error" }
}
'''.parseAndInfer.asserting [
findByText('''if (bool) 2 else "error"''').assertIncompatibleTypesIssue("String", "Number")
assertMethodSignature("() => (Number|String)", "obj.boolean")
]
}

@Test
def void methodParamVarType() {
'''
program {
const n = 0
const s = ""
assert.equals(n, s)
}
'''.parseAndInfer.asserting [
findByText("assert.equals(n, s)", WMemberFeatureCall).assertIncompatibleTypesIssue("String", "Number")
]
}

def assertIncompatibleTypesIssue(EObject element, String type1, String type2) {
element.assertAnyIssueInElement(
'''Type system: expected <<«type1»>> but found <<«type2»>>''',
'''Type system: expected <<«type2»>> but found <<«type1»>>'''
)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ class MethodTypeInferenceTestCase extends AbstractWollokTypeSystemTestCase {
assertMethodSignature("(Number) => Void", 'GolondrinaIneficiente.comer')
]
}

@Test
def void testMethodInferredFromSuperMethodWithSuperInvocation() {
'''
Expand Down Expand Up @@ -250,11 +250,29 @@ class MethodTypeInferenceTestCase extends AbstractWollokTypeSystemTestCase {
}
'''.parseAndInfer.asserting [
assertTypeOf(classTypeFor(NUMBER), "number")
findByText("number.div(1).isBig(true, 1)", WMemberFeatureCall).assertIssuesInElement("Number does not understand isBig(true, 1)")
findByText("number.div(1).isBig(true, 1)", WMemberFeatureCall).assertIssuesInElement(
"Number does not understand isBig(true, 1)")
]
}


@Test
def void unionType() {
'''
object testing {
method test1() {
obj.x("")
obj.x(0)
}
}
object obj {
method x(_x) { }
}
'''.parseAndInfer.asserting [
noIssues
assertMethodSignature("((Number|String)) => Void", "obj.x")
]
}

@Test
def void badAnyInference() {
'''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import org.eclipse.xpect.runner.Xpect
import org.eclipse.xpect.runner.XpectRunner
import org.eclipse.xpect.runner.XpectSuiteClasses
import org.eclipse.xpect.xtext.lib.setup.ThisModel
import org.eclipse.xpect.xtext.lib.setup.ThisResource
import org.eclipse.xpect.xtext.lib.tests.ValidationTest
import org.eclipse.xpect.xtext.lib.tests.ValidationTestModuleSetup.ConsumedIssues
import org.eclipse.xpect.xtext.lib.util.XtextOffsetAdapter.IEStructuralFeatureAndEObject
Expand All @@ -26,10 +27,8 @@ import org.uqbar.project.wollok.wollokDsl.WMemberFeatureCall
import org.uqbar.project.wollok.wollokDsl.WMethodDeclaration

import static extension org.uqbar.project.wollok.model.WollokModelExtensions.*
import static extension org.uqbar.project.wollok.typesystem.constraints.WollokModelPrintForDebug.*
import org.eclipse.xpect.xtext.lib.setup.ThisResource

import static extension org.uqbar.project.wollok.typesystem.TypeSystemUtils.*
import static extension org.uqbar.project.wollok.typesystem.constraints.WollokModelPrintForDebug.*

/**
* Test class for extending xpect to have tests on static proposals (content assist)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ program p {
// XPECT type at c6 --> {() => Number}
const c6 = { if (bool) return 1 else return 2 }

// XPECT type at c7 --> {() => (Number|String)}
// XPECT type at c7 --> {() => Number}
const c7 = {
if (bool) { return 1 }
return "2"
return 2
}

// XPECT type at c8 --> {() => Number}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ describe "with fixture" {

test "test with self" {
n = self.number()
// XPECT type at s --> String
var s = ""
assert.equals(n, s)
// XPECT type at expected --> Number
var expected
assert.equals(n, expected)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Point {
class Point3D inherits Point {
const z = 0

override method tipar() = z.even()
override method tipar() = super() + z
}

class TestConstructors {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ class Golondrina {
// XPECT methodType at vola --> (Number) => Void
method vola(kilometros) { energia = energia - kilometros * 10 }

// XPECT methodType at come --> (Number) => Void
method come(grms) { energia += grms * 0.10 }
// XPECT methodType at come --> ((alpiste|manzana)) => Void
method come(comida) { energia += comida.energia() * 0.10 }
}

object alpiste {
method energia() = 1
}

object manzana {
method energia() = 1
}

object pepita {
Expand All @@ -20,6 +28,9 @@ class Entrenador {
// XPECT type at estrategia --> {(Golondrina) => Void}
const estrategia = { ave => ave.vola(5) }

// XPECT methodType at darAlpiste --> (Golondrina) => Void
method darAlpiste(ave) { ave.come(alpiste) }

// XPECT methodType at entrena --> (Golondrina) => Void
method entrena(ave) { ave.vola(5) }

Expand All @@ -37,7 +48,7 @@ class Entrenador {

ave.vola(1)

// XPECT warnings --> "Golondrina does not understand come(). However other methods exist with different argument count: come(grms)" at "ave.come()"
// XPECT warnings --> "Golondrina does not understand come(). However other methods exist with different argument count: come(comida)" at "ave.come()"
return ave.come()
}

Expand All @@ -63,7 +74,7 @@ class Entrenador {
// XPECT methodType at entrenarConEstrategia --> (Golondrina) => Void
method entrenarConEstrategia(ave) { self.estrategia().apply(ave) }

// XPECT methodType at alimentar --> (Golondrina, Number) => Void
// XPECT methodType at alimentar --> (Golondrina, (alpiste|manzana)) => Void
method alimentar(golondrina, comida) {
const c = { g => g.come(comida) }
c.apply(golondrina)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class GolondrinaMentirosa inherits Golondrina {


class EntrenadorChanta inherits EntrenadorDeGolondrinas {
// XPECT methodType at alimentar --> (Ave) => Void
// XPECT methodType at alimentar --> (Golondrina) => Void
override method alimentar(ave) {
super(new GolondrinaMentirosa(1))
}
Expand All @@ -81,7 +81,7 @@ class EntrenadorDeGolondrinas inherits EntrenadorDeAves {
g.vola()
}

// XPECT methodType at alimentar --> (Ave) => Void
// XPECT methodType at alimentar --> (Golondrina) => Void
override method alimentar(ave) {
super(new Golondrina())
}
Expand Down Expand Up @@ -109,13 +109,16 @@ class EntrenadorDeAves {
ave = a
}

// XPECT methodType at alimentar --> (Ave) => Void
// XPECT methodType at alimentar --> (Golondrina) => Void
method alimentar(ave) { ave.come(10) }

// XPECT methodType at pajaro --> () => Ave
method pajaro() = new Ave()

method alimentarAve() { self.alimentar(new Ave()) }
method alimentarAve() {
// TODO: Fail!
// self.alimentar(new Ave())
}

method alimentarFavorita() { ave.come(1) }
}
Expand Down
Loading

0 comments on commit f7f3f84

Please sign in to comment.