Skip to content

[Constraint solver] Use the type representative in the "occurs" check. #5475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
bool wantRvalue = kind == ConstraintKind::Equal;
if (typeVar1) {
// Simplify the right-hand type and perform the "occurs" check.
typeVar1 = getRepresentative(typeVar1);
type2 = simplifyType(type2);
if (typeVarOccursInType(typeVar1, type2))
return formUnsolvedResult();
Expand Down Expand Up @@ -1332,10 +1333,11 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return SolutionKind::Solved;
}

// Simplify the left-hand type and perform the "occurs" check.
type1 = simplifyType(type1);
if (typeVarOccursInType(typeVar2, type1))
return formUnsolvedResult();
// Simplify the left-hand type and perform the "occurs" check.
typeVar2 = getRepresentative(typeVar2);
type1 = simplifyType(type1);
if (typeVarOccursInType(typeVar2, type1))
return formUnsolvedResult();

// If we want an rvalue, get the rvalue.
if (wantRvalue)
Expand All @@ -1355,6 +1357,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
case ConstraintKind::BindParam: {
if (typeVar2 && !typeVar1) {
// Simplify the left-hand type and perform the "occurs" check.
typeVar2 = getRepresentative(typeVar2);
type1 = simplifyType(type1);
if (typeVarOccursInType(typeVar2, type1))
return formUnsolvedResult();
Expand All @@ -1367,6 +1370,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
return SolutionKind::Solved;
} else if (typeVar1 && !typeVar2) {
// Simplify the right-hand type and perform the "occurs" check.
typeVar1 = getRepresentative(typeVar1);
type2 = simplifyType(type2);
if (typeVarOccursInType(typeVar1, type2))
return formUnsolvedResult();
Expand Down
8 changes: 0 additions & 8 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,6 @@ bool ConstraintSystem::typeVarOccursInType(TypeVariableType *typeVar,
void ConstraintSystem::assignFixedType(TypeVariableType *typeVar, Type type,
bool updateState) {

// If the type to be fixed is an optional type that wraps the type parameter
// itself, we do not want to go through with the assignment. To do so would
// force the type variable to be adjacent to itself.
if (auto optValueType = type->getOptionalObjectType()) {
if (optValueType->isEqual(typeVar))
return;
}

typeVar->getImpl().assignFixedType(type, getSavedBindings());

if (!updateState)
Expand Down
5 changes: 5 additions & 0 deletions test/Constraints/generics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,8 @@ func testFixItNested() {
FullyGeneric<Any>()
)
}

// rdar://problem/26845038
func occursCheck26845038(a: [Int]) {
_ = Array(a)[0]
}
6 changes: 6 additions & 0 deletions test/Constraints/optional.swift
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,9 @@ protocol PPPP {
func compare<T: PPPP>(v: T, u: T!) -> Bool {
return v ++++ u
}

func sr2752(x: String?, y: String?) {
_ = x.map { xx in
y.map { _ in "" } ?? "\(xx)"
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// RUN: not %target-swift-frontend %s -parse
// REQUIRES: asserts

public protocol I {
associatedtype X : Equatable
Expand Down
57 changes: 57 additions & 0 deletions validation-test/Sema/type_checker_crashers_fixed/sr1512.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// RUN: not %target-swift-frontend %s -parse

public struct CollectionWrapper<C:RangeReplaceableCollection where C.Index:Comparable> {

public private(set) var collection : C

private init(wrappingCollection: C) {
collection = wrappingCollection
}
}

// Export Collection API

extension CollectionWrapper : Collection {

public var startIndex: C.Index { return collection.startIndex }
public var endIndex : C.Index { return collection.endIndex }

public func makeIterator() -> C.Iterator {
return collection.makeIterator()
}

public subscript (position: C.Index) -> C.Iterator.Element { return collection[position] }

public subscript (bounds: Range<C.Index>) -> C.SubSequence { return collection[bounds] }

public func prefix(upTo end: C.Index) -> C.SubSequence { return collection.prefix(upTo: end) }

public func suffix(from start: C.Index) -> C.SubSequence { return collection.suffix(from: start) }

public func prefix(through position: C.Index) -> C.SubSequence { return collection.prefix(through: position) }

public var isEmpty: Bool { return collection.isEmpty }

public var count: C.IndexDistance { return collection.count }

public var first: C.Iterator.Element? { return collection.first }

public func index(after idx: C.Index) -> C.Index { return collection.index(after: idx) }

public func index(_ idx: C.Index, offsetBy offset: C.IndexDistance, limitedBy limit: C.Index? = nil) -> C.Index {
return collection.index(idx, offsetBy: offset, limitedBy: limit)
}
}

// Export RangeReplaceableCollection API

extension CollectionWrapper : RangeReplaceableCollection {

public init() {
self.init(wrappingCollection: C())
}

public mutating func replaceSubrange<D : Collection where D.Iterator.Element == C.Iterator.Element>(_ subRange: Range<C.Index>, with newElements: D) {
collection.replaceSubrange(subRange, with: newElements)
}
}
22 changes: 22 additions & 0 deletions validation-test/Sema/type_checker_crashers_fixed/sr1902.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// RUN: not %target-swift-frontend %s -parse
struct A {
var a: Int32 { return 0 }
}

struct B {
var b: Int64 { return 0 }
}

struct C {
var c: Int64 { return 0 }
}

class S {
var a: A? = A()
var b: B? = B()
var c: C? = C()
var result: Int64? { return a?.a ?? b?.b ?? c?.c }
}

let s = S()
print(s.result)
62 changes: 62 additions & 0 deletions validation-test/Sema/type_checker_crashers_fixed/sr2635.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// RUN: %target-swift-frontend %s -parse

//
// main.swift
// TypeBasics
//
// Created by David Scrève on 16/11/2014.
// Copyright (c) 2014 David Scrève. All rights reserved.
//

let constante : String = "Hello World"


let constante2 = "Hello World"

let caractere : Character = Array(constante.characters)[0]

let caractere2 : Character = "A"

var variable : String


var chaine = "Bonjour le monde"


var nombre : Int = 3

nombre=5

var valeur : Int32

valeur = Int32(nombre)



print("la valeur vaut : \(valeur)")


if (valeur > 3)
{
print(">3")
}
else
{
print("<=3")
}

switch(valeur)
{
case 0:
print("0");

case 1,2:
print("1");

case 10...100:
print("Interval");

default:
print("default");
}