<commit_before>//===--- RequirementLowering.cpp - Requirement inference and desugaring ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements logic for desugaring requirements, for example breaking
// down 'T : P & Q' into 'T : P' and 'T : Q', as well as requirement inference,
// where an occurrence of 'Set<T>' in a function signature introduces the
// requirement 'T : Hashable' from the generic signature of 'struct Set'.
//
//===----------------------------------------------------------------------===//

#include "RequirementLowering.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/RequirementSignature.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeMatcher.h"
#include "swift/AST/TypeRepr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SetVector.h"
#include "RewriteContext.h"

using namespace swift;
using namespace rewriting;

/// Desugar a same-type requirement that possibly has concrete types on either
/// side into a series of same-type and concrete-type requirements where the
/// left hand side is always a type parameter.
static void desugarSameTypeRequirement(Type lhs, Type rhs, SourceLoc loc,
                                       SmallVectorImpl<Requirement> &result,
                                       SmallVectorImpl<RequirementError> &errors) {
  class Matcher : public TypeMatcher<Matcher> {
    SourceLoc loc;
    SmallVectorImpl<Requirement> &result;
    SmallVectorImpl<RequirementError> &errors;

  public:
    bool recordedErrors = false;
    bool recordedRequirements = false;

    explicit Matcher(SourceLoc loc,
                     SmallVectorImpl<Requirement> &result,
                     SmallVectorImpl<RequirementError> &errors)
      : loc(loc), result(result), errors(errors) {}

    bool alwaysMismatchTypeParameters() const { return true; }

    bool mismatch(TypeBase *firstType, TypeBase *secondType,
                  Type sugaredFirstType) {
      if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            sugaredFirstType, secondType);
        recordedRequirements = true;
        return true;
      }

      if (firstType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            sugaredFirstType, secondType);
        recordedRequirements = true;
        return true;
      }

      if (secondType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            secondType, firstType);
        recordedRequirements = true;
        return true;
      }

      errors.push_back(
          RequirementError::forConcreteTypeMismatch(firstType,
                                                    secondType,
                                                    loc));
      recordedErrors = true;
      return true;
    }
  } matcher(loc, result, errors);

  (void) matcher.match(lhs, rhs);

  // If neither side is directly a type parameter, the type parameter
  // must be in structural position where the enclosing type is redundant.
  if (!lhs->isTypeParameter() && !rhs->isTypeParameter() &&
      !matcher.recordedErrors) {
    // FIXME: Add a tailored error message when requirements were
    // recorded, e.g. Array<Int> == Array<T>. The outer type is
    // redundant, but the inner requirement T == Int is not.
    errors.push_back(RequirementError::forRedundantRequirement(
        {RequirementKind::SameType, lhs, rhs}, loc));
  }
}

static void desugarSuperclassRequirement(Type subjectType,
                                         Type constraintType,
                                         SourceLoc loc,
                                         SmallVectorImpl<Requirement> &result,
                                         SmallVectorImpl<RequirementError> &errors) {
  if (!subjectType->isTypeParameter()) {
    Requirement requirement(RequirementKind::Superclass,
                            subjectType, constraintType);
    if (constraintType->isExactSuperclassOf(subjectType)) {
      errors.push_back(
          RequirementError::forRedundantRequirement(requirement, loc));
    } else {
      errors.push_back(
          RequirementError::forConflictingRequirement(requirement, loc));
    }

    return;
  }

  result.emplace_back(RequirementKind::Superclass, subjectType, constraintType);
}

static void desugarLayoutRequirement(Type subjectType,
                                     LayoutConstraint layout,
                                     SourceLoc loc,
                                     SmallVectorImpl<Requirement> &result,
                                     SmallVectorImpl<RequirementError> &errors) {
  if (!subjectType->isTypeParameter()) {
    Requirement requirement(RequirementKind::Layout,
                            subjectType, layout);
    if (layout->isClass() && subjectType->isAnyClassReferenceType()) {
      errors.push_back(
          RequirementError::forRedundantRequirement(requirement, loc));
    } else {
      errors.push_back(
          RequirementError::forConflictingRequirement(requirement, loc));
    }

    return;
  }

  result.emplace_back(RequirementKind::Layout, subjectType, layout);
}

/// Desugar a protocol conformance requirement by splitting up protocol
/// compositions on the right hand side into conformance and superclass
/// requirements.
static void desugarConformanceRequirement(Type subjectType, Type constraintType,
                                          SourceLoc loc,
                                          SmallVectorImpl<Requirement> &result,
                                          SmallVectorImpl<RequirementError> &errors) {
  // Fast path.
  if (constraintType->is<ProtocolType>()) {
    if (!subjectType->isTypeParameter()) {
      // Check if the subject type actually conforms.
      auto *protoDecl = constraintType->castTo<ProtocolType>()->getDecl();
      auto *module = protoDecl->getParentModule();
      auto conformance = module->lookupConformance(subjectType, protoDecl);
      if (conformance.isInvalid()) {
        errors.push_back(RequirementError::forConflictingRequirement(
            {RequirementKind::Conformance, subjectType, constraintType}, loc));
        return;
      }

      errors.push_back(RequirementError::forRedundantRequirement(
          {RequirementKind::Conformance, subjectType, constraintType}, loc));

      assert(conformance.isConcrete());
      auto *concrete = conformance.getConcrete();

      // Introduce conditional requirements if the subject type is concrete.
      for (auto req : concrete->getConditionalRequirements()) {
        desugarRequirement(req, result, errors);
      }
      return;
    }

    result.emplace_back(RequirementKind::Conformance, subjectType,
                        constraintType);
    return;
  }

  if (auto *paramType = constraintType->getAs<ParameterizedProtocolType>()) {
    desugarConformanceRequirement(subjectType, paramType->getBaseType(),
                                  loc, result, errors);

    SmallVector<Requirement, 2> reqs;
    paramType->getRequirements(subjectType, reqs);

    for (const auto &req : reqs)
      desugarRequirement(req, result, errors);

    return;
  }
<commit_msg>RequirementMachine: Don't assert on abstract conformance in desugarConformanceRequirement()<commit_after>//===--- RequirementLowering.cpp - Requirement inference and desugaring ---===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements logic for desugaring requirements, for example breaking
// down 'T : P & Q' into 'T : P' and 'T : Q', as well as requirement inference,
// where an occurrence of 'Set<T>' in a function signature introduces the
// requirement 'T : Hashable' from the generic signature of 'struct Set'.
//
//===----------------------------------------------------------------------===//

#include "RequirementLowering.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/Requirement.h"
#include "swift/AST/RequirementSignature.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/AST/TypeMatcher.h"
#include "swift/AST/TypeRepr.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SetVector.h"
#include "RewriteContext.h"

using namespace swift;
using namespace rewriting;

/// Desugar a same-type requirement that possibly has concrete types on either
/// side into a series of same-type and concrete-type requirements where the
/// left hand side is always a type parameter.
static void desugarSameTypeRequirement(Type lhs, Type rhs, SourceLoc loc,
                                       SmallVectorImpl<Requirement> &result,
                                       SmallVectorImpl<RequirementError> &errors) {
  class Matcher : public TypeMatcher<Matcher> {
    SourceLoc loc;
    SmallVectorImpl<Requirement> &result;
    SmallVectorImpl<RequirementError> &errors;

  public:
    bool recordedErrors = false;
    bool recordedRequirements = false;

    explicit Matcher(SourceLoc loc,
                     SmallVectorImpl<Requirement> &result,
                     SmallVectorImpl<RequirementError> &errors)
      : loc(loc), result(result), errors(errors) {}

    bool alwaysMismatchTypeParameters() const { return true; }

    bool mismatch(TypeBase *firstType, TypeBase *secondType,
                  Type sugaredFirstType) {
      if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            sugaredFirstType, secondType);
        recordedRequirements = true;
        return true;
      }

      if (firstType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            sugaredFirstType, secondType);
        recordedRequirements = true;
        return true;
      }

      if (secondType->isTypeParameter()) {
        result.emplace_back(RequirementKind::SameType,
                            secondType, firstType);
        recordedRequirements = true;
        return true;
      }

      errors.push_back(
          RequirementError::forConcreteTypeMismatch(firstType,
                                                    secondType,
                                                    loc));
      recordedErrors = true;
      return true;
    }
  } matcher(loc, result, errors);

  (void) matcher.match(lhs, rhs);

  // If neither side is directly a type parameter, the type parameter
  // must be in structural position where the enclosing type is redundant.
  if (!lhs->isTypeParameter() && !rhs->isTypeParameter() &&
      !matcher.recordedErrors) {
    // FIXME: Add a tailored error message when requirements were
    // recorded, e.g. Array<Int> == Array<T>. The outer type is
    // redundant, but the inner requirement T == Int is not.
    errors.push_back(RequirementError::forRedundantRequirement(
        {RequirementKind::SameType, lhs, rhs}, loc));
  }
}

static void desugarSuperclassRequirement(Type subjectType,
                                         Type constraintType,
                                         SourceLoc loc,
                                         SmallVectorImpl<Requirement> &result,
                                         SmallVectorImpl<RequirementError> &errors) {
  if (!subjectType->isTypeParameter()) {
    Requirement requirement(RequirementKind::Superclass,
                            subjectType, constraintType);
    if (constraintType->isExactSuperclassOf(subjectType)) {
      errors.push_back(
          RequirementError::forRedundantRequirement(requirement, loc));
    } else {
      errors.push_back(
          RequirementError::forConflictingRequirement(requirement, loc));
    }

    return;
  }

  result.emplace_back(RequirementKind::Superclass, subjectType, constraintType);
}

static void desugarLayoutRequirement(Type subjectType,
                                     LayoutConstraint layout,
                                     SourceLoc loc,
                                     SmallVectorImpl<Requirement> &result,
                                     SmallVectorImpl<RequirementError> &errors) {
  if (!subjectType->isTypeParameter()) {
    Requirement requirement(RequirementKind::Layout,
                            subjectType, layout);
    if (layout->isClass() && subjectType->isAnyClassReferenceType()) {
      errors.push_back(
          RequirementError::forRedundantRequirement(requirement, loc));
    } else {
      errors.push_back(
          RequirementError::forConflictingRequirement(requirement, loc));
    }

    return;
  }

  result.emplace_back(RequirementKind::Layout, subjectType, layout);
}

/// Desugar a protocol conformance requirement by splitting up protocol
/// compositions on the right hand side into conformance and superclass
/// requirements.
static void desugarConformanceRequirement(Type subjectType, Type constraintType,
                                          SourceLoc loc,
                                          SmallVectorImpl<Requirement> &result,
                                          SmallVectorImpl<RequirementError> &errors) {
  // Fast path.
  if (constraintType->is<ProtocolType>()) {
    if (!subjectType->isTypeParameter()) {
      // Check if the subject type actually conforms.
      auto *protoDecl = constraintType->castTo<ProtocolType>()->getDecl();
      auto *module = protoDecl->getParentModule();
      auto conformance = module->lookupConformance(subjectType, protoDecl);
      if (conformance.isInvalid()) {
        errors.push_back(RequirementError::forConflictingRequirement(
            {RequirementKind::Conformance, subjectType, constraintType}, loc));
        return;
      }

      errors.push_back(RequirementError::forRedundantRequirement(
          {RequirementKind::Conformance, subjectType, constraintType}, loc));

      if (conformance.isConcrete()) {
        // Introduce conditional requirements if the conformance is concrete.
        for (auto req : conformance.getConcrete()->getConditionalRequirements()) {
          desugarRequirement(req, result, errors);
        }
      }

      return;
    }

    result.emplace_back(RequirementKind::Conformance, subjectType,
                        constraintType);
    return;
  }

  if (auto *paramType = constraintType->getAs<ParameterizedProtocolType>()) {
    desugarConformanceRequirement(subjectType, paramType->getBaseType(),
                                  loc, result, errors);

    SmallVector<Requirement, 2> reqs;
    paramType->getRequirements(subjectType, reqs);

    for (const auto &req : reqs)
      desugarRequirement(req, result, errors);

    return;
  }

{'fraction_non_alphanumeric': 0.11367422786107907, 'fraction_numerical': 0.0008970908624887864, 'mean_word_length': 2.3362548097477553, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 85, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 50, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3101639', 'n_tokens_mistral': 3955, 'n_tokens_neox': 3831, 'n_words': 974}